Comment ajuster UIToolBar à gauche et à droite

Je crée un UIToolbar avec du code et un autre avec un générateur d’interface. Mais, découvrez les deux barres d’outils ayant des rembourrages gauche et droit différents, illustrés ci-dessous:

Depuis Interface Builder:

entrer la description de l'image ici

Du code:

entrer la description de l'image ici

UIImage *buttonImage = [[UIImage imageNamed:@"button.png"] stretchableImageWithLeftCapWidth:10 topCapHeight:0]; UIButton *btnTest = [UIButton buttonWithType:UIButtonTypeCustom]; [btnTest setBackgroundImage:buttonImage forState:UIControlStateNormal]; [btnTest setTitle:@"Back" forState:UIControlStateNormal]; [btnTest.titleLabel setFont:[UIFont boldSystemFontOfSize:13]]; [btnTest setBackgroundImage:[imgToolbarButton stretchableImageWithLeftCapWidth:5 topCapHeight:0] forState:UIControlStateNormal]; [btnTest addTarget:self action:@selector(clearDateEdit:) forControlEvents:UIControlEventTouchUpInside]; btnTest.frame = CGRectMake(0.0, 0.0, 50, 30); UIBarButtonItem *btnTestItem = [[UIBarButtonItem alloc] initWithCustomView:btnTest]; [self.toolbar setItems:[NSArray arrayWithObjects:btnTestItem,nil]]; [btnTestItem release]; 

Ma question est la suivante: comment puis-je ajuster le remplissage gauche et droit de UIToolbar par code?

Mettre à jour

J’ai découvert que ce problème d’alignement n’arrivait qu’à UIBarButtonItem avec customView de UIButton, l’alignement est bien avec UIBarButtonItem. Toute idée de la cause ou pour résoudre ce problème.

La seule solution que je puisse imaginer en ce moment est de définir manuellement le cadre.

J’ai eu le même problème, et il y a une astuce que vous pouvez faire avec un UIBarButtonSystemItemFixedSpace, ajoutez l’un d’entre eux avec une largeur négative avant votre premier bouton et après votre dernier bouton et cela déplacera le bouton sur le bord.

Par exemple, pour supprimer la marge de droite, ajoutez l’élément de barre FixedSpace suivant comme dernier élément:

 UIBarButtonItem *negativeSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; negativeSeparator.width = -12; 

Les marges à gauche et à droite sont 12px.

Mise à jour pour iOS7 – les marges sont 16px sur iPhone et 20px sur iPad!

Avant iOS 11

Vous aviez trois solutions possibles:

  • Le premier utilisait un élément d’espace UIBarButtonItem (barButtonSystemItem: .fixedSpace…) avec une largeur négative
  • L’autre consistait à remplacer alignmentRectInsets sur la vue personnalisée.
  • Le dernier, si vous utilisez UIButton comme vue personnalisée de votre élément, vous pouvez remplacer contentEdgeInsets et hitTest (_: with 🙂

Absolument, la première solution semble meilleure que les autres

 UIBarButtonItem *negativeSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; negativeSeparator.width = -12; 

si vous utilisez swift, le code sera comme ceci

 var negativeSeparator = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) negativeSeparator.width = -12 

Après iOS 11 (contient iOS 11)

Malheureusement, toute la solution ne peut pas être utilisée dans iOS 11

  • première solution: la définition d’une largeur négative ne fonctionne plus
  • deuxième solution: override alignmentRectInsets provoquera une partie de l’élément ne recevra plus de contacts
  • la dernière solution: je pense que hitTest de remplacement (_: avec 🙂 n’est pas une bonne idée, ne le faites pas s’il vous plaît!

Vous pouvez également voir des suggestions sur les forums de développeurs , mais après avoir examiné tous les commentaires, vous trouverez des suggestions sur ce sujet: créer une sous-classe UINavigationBar personnalisée et faire quelque chose de complexe.

Oh mon dieu, tout ce que je veux faire est de changer le rembourrage, pas la barre de navigation!

Heureusement, nous pouvons le faire avec une astuce dans iOS 11!

Et c’est parti:

1. créer un bouton personnalisé

  • définir translatesAutoresizingMaskIntoConstraints comme false
  • remplacer alignmentRectInsets
    • élément à droite utiliser UIEdgeInsets (en haut: 0, à gauche: -8, en bas: 0, à droite: 8)
    • élément à gauche utiliser UIEdgeInsets (en haut: 0, à gauche: 8, en bas: 0, à droite: -8)

      si vous ne connaissez pas alignmentRectInsets, vous pouvez d’abord lire ce blog

version rapide

 var customButton = UIButton(type: .custom) customButton.overrideAlignmentRectInsets = UIEdgeInsets(top: 0, left: x, bottom: 0, right: -x) // you should do this in your own custom class customButton.translatesAutoresizingMaskIntoConstraints = false; 

version objective-c

 UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom]; customButton.overrideAlignmentRectInsets = UIEdgeInsetsMake(0, x, 0, -x); // you should do this in your own custom class customButton.translatesAutoresizingMaskIntoConstraints = NO; 

2. créer un article avec votre bouton personnalisé

version rapide

 var item = UIBarButtonItem(customView: customButton) 

version objective-c

 UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:customButton] 

3. créer un type fixedSpace UIBarButtonItem avec une largeur positive

définir une valeur positive , pas une valeur négative

version rapide

 var positiveSeparator = UIBarButtonItem(barButtonSystemItem:.fixedSpace, target: nil, action: nil) positiveSeparator.width = 8 

version objective-c

 UIBarButtonItem *positiveSeparator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; positiveSeparator.width = 8; 

4. définir un tableau à gauche ou à droite

type fixedSpace L’élément UIBarButton doit être le premier élément du tableau.

version rapide

 self.navigationItem.leftBarButtonItems = [positiveSeparator, item, ...] 

version objective-c

 self.navigationItem.leftBarButtonItems = @{positiveSeparator, item, ...} 

Bien joué

Après avoir effectué toutes les étapes, vous verrez que votre rembourrage devient plus petit et que la zone de saisie semble correcte!

Si vous trouvez quelque chose qui ne va pas, faites-le moi savoir! Je vais faire de mon mieux pour répondre à votre question!

Remarque

Avant iOS 11, vous devez vous soucier de la largeur de l’écran de l’appareil; si l’écran est de 5,5 pouces, le négatif est de -12 pt, sur les autres écrans de -8pt.

Si vous utilisez ma solution sur iOS 11, vous n’avez pas à vous soucier de l’écran de l’appareil, définissez simplement 8pt. Vous devez vous soucier de la position de l’élément dans la barre de navigation, à gauche ou à droite.

Vous voulez plus de zone de claquettes

Si vous voulez promettre que votre zone de frappe est supérieure à 44 * 44, vous pouvez remplacer la méthode ci-dessous

 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ CGSize acturalSize = self.frame.size; CGSize minimumSize = kBarButtonMinimumTapAreaSize; CGFloat verticalMargin = acturalSize.height - minimumSize.height >= 0 ? 0 : ((minimumSize.height - acturalSize.height ) / 2); CGFloat horizontalMargin = acturalSize.width - minimumSize.width >= 0 ? 0 : ((minimumSize.width - acturalSize.width ) / 2); CGRect newArea = CGRectMake(self.bounds.origin.x - horizontalMargin, self.bounds.origin.y - verticalMargin, self.bounds.size.width + 2 * horizontalMargin, self.bounds.size.height + 2 * verticalMargin); return CGRectContainsPoint(newArea, point); } 

C’est une excellente question et même avec les solutions fournies – cela n’a pas résolu le problème sur iOS11.

SOLUTION DE TRAVAIL

Si vous créez une nouvelle extension de UIButton :

 class BarButton: UIButton { override var alignmentRectInsets: UIEdgeInsets { return UIEdgeInsetsMake(0, 16, 0, 16) } } 

Ensuite, lorsque vous l’utilisez dans votre mise en page:

 lazy var btnLogin: BarButton = { let btn = BarButton(type: .custom) // Add your button settings btn.widthAnchor.constraint(equalToConstant: self.frame.size.width).isActive = true btn.heightAnchor.constraint(equalToConstant: 50).isActive = true btn.translatesAutoresizingMaskIntoConstraints = false return btn }() 

Cela a résolu un problème très ennuyeux, si vous avez des problèmes, donnez-moi un coup de fil.

utilisez ce bouton

 UIBarButtonItem *spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 

J’ai rencontré le même problème. Enfin, j’ai résolu ce problème en sous-classant UIToolbar et en remplaçant la méthode des sous-vues de présentation.

 - (void)layoutSubviews { [super layoutSubviews]; if (leftItem_ && leftItem_.customView && [leftItem_.customView isKindOfClass:[UIButton class]]) { CGRect newFrame = leftItem_.customView.frame; newFrame.origin.x = 0; // reset the original point x to 0; default is 12, wired number leftItem_.customView.frame = newFrame; } if (rightItem_ && rightItem_.customView && [rightItem_.customView isKindOfClass:[UIButton class]]) { CGRect newFrame = rightItem_.customView.frame; newFrame.origin.x = self.frame.size.width - CGRectGetWidth(newFrame); rightItem_.customView.frame = newFrame; } } 

Vous pouvez modifier le décalage et la largeur de votre barre d’outils si vous souhaitez utiliser customview (initWithCustomView)

 [myToolBar setFrame:CGRectMake(-10, 0, [UIScreen mainScreen].bounds.size.width+10, 44)]; 

Je suis tombé sur cela en essayant de centrer une barre d’outils en tant que sous-vue d’un UIButton. Comme la barre d’outils devait être de petite largeur, la meilleure solution était un bouton flexible de chaque côté:

 UIBarButtonItem flexibleButtonItemLeft = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIBarButtonItem centeredButtonItem = ... UIBarButtonItem flexibleButtonItemRight = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; UIToolbar toolbar = ... toolbar.items = @[flexibleButtonItemLeft, centeredButtonItem, flexibleButtonItemRight]; 

Enfin, pour avoir une image d’arrière-plan personnalisée pour UIBarButtonItem et pour adapter l’alignement, j’ai abandonné UIBarButtonItem et ajouté UIButton manuellement.

 UIImage *buttonImage = [[UIImage imageNamed:@"button.png"] stretchableImageWithLeftCapWidth:10 topCapHeight:0]; UIButton *btnTest = [UIButton buttonWithType:UIButtonTypeCustom]; [btnTest setBackgroundImage:buttonImage forState:UIControlStateNormal]; [btnTest setTitle:@"Back" forState:UIControlStateNormal]; [btnTest.titleLabel setFont:[UIFont boldSystemFontOfSize:13]]; [btnTest setBackgroundImage:[imgToolbarButton stretchableImageWithLeftCapWidth:5 topCapHeight:0] forState:UIControlStateNormal]; [btnTest addTarget:self action:@selector(clearDateEdit:) forControlEvents:UIControlEventTouchUpInside]; btnTest.frame = CGRectMake(0.0, 0.0, 50, 30); [self.toolbar addSubview:btnTest]; [btnTestItem release]; 

Je pense qu’une manière délicate est d’utiliser Aspects (ou la méthode swizzling),

 [UINavigationBar aspect_hookSelector:@selector(layoutSubviews) withOptions:AspectPositionAfter usingBlock:^(id info){ UINavigationBar *bar = info.instance; //[bar layoutSubviews]; if ([bar isKindOfClass:[UINavigationBar class]]) { if (@available(iOS 11, *)) { bar.layoutMargins = UIEdgeInsetsZero; for (UIView *subview in bar.subviews) { if ([NSSsortingngFromClass([subview class]) containsSsortingng:@"ContentView"]) { UIEdgeInsets oEdges = subview.layoutMargins; subview.layoutMargins = UIEdgeInsetsMake(0, 0, 0, oEdges.right); } } } } } error:nil];