Modifier la position de UIBarButtonItem dans UINavigationBar

Comment puis-je modifier la position d’un UIBarButtonItem dans un UINavigationBar? Je voudrais que mon bouton soit environ 5 fois plus haut que sa position normale.

Il n’y a pas de moyen particulièrement efficace de le faire. Votre meilleur pari est de sous-classer UINavigationBar et de remplacer layoutSubviews pour appeler [super layoutSubviews] , puis rechercher et repositionner la vue du bouton.

Ce code crée un bouton retour pour UINavigationBar avec un arrière-plan d’image et une position personnalisée. L’astuce consiste à créer une vue intermédiaire et à modifier ses limites.

 UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom]; UIImage *backBtnImage = [UIImage imageNamed:@"btn-back"]; UIImage *backBtnImagePressed = [UIImage imageNamed:@"btn-back-pressed"]; [backBtn setBackgroundImage:backBtnImage forState:UIControlStateNormal]; [backBtn setBackgroundImage:backBtnImagePressed forState:UIControlStateHighlighted]; [backBtn addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside]; backBtn.frame = CGRectMake(0, 0, 63, 33); UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 63, 33)]; backButtonView.bounds = CGRectOffset(backButtonView.bounds, -14, -7); [backButtonView addSubview:backBtn]; UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:backButtonView]; self.navigationItem.leftBarButtonItem = backButton; 

J’ai résolu en utilisant la vue transformée et personnalisée:

(Rapide)

  // create the button let suggestImage = UIImage(named: "tab-item-popcorn-on")!.imageWithRenderingMode(.AlwaysOriginal) let suggestButton = UIButton(frame: CGRectMake(0, 0, 40, 40)) suggestButton.setBackgroundImage(suggestImage, forState: .Normal) suggestButton.addTarget(self, action: Selector("suggesMovie:"), forControlEvents:.TouchUpInside) // here where the magic happens, you can shift it where you like suggestButton.transform = CGAffineTransformMakeTranslation(10, 0) // add the button to a container, otherwise the transform will be ignored let suggestButtonContainer = UIView(frame: suggestButton.frame) suggestButtonContainer.addSubview(suggestButton) let suggestButtonItem = UIBarButtonItem(customView: suggestButtonContainer) // add button shift to the side navigationItem.rightBarButtonItem = suggestButtonItem 

Pour ceux d’entre vous qui développent pour iOS 5 qui ont trébuché sur ce sujet et ont été découragés … Essayez quelque chose comme ceci:

 float my_offset_plus_or_minus = 3.0f; UIBarButtonItem * item = [[UIBarButtonItem alloc] initWithTitle:@"title" style:UIBarButtonItemStyleDone target:someObject action:@selector(someMessage)]; [item setBackgroundVerticalPositionAdjustment:my_offset_plus_or_minus forBarMesortingcs:UIBarMesortingcsDefault]; 

Le meilleur moyen est de sous-classer votre UINavigationBar, comme décrit ici: https://stackoverflow.com/a/17434530/1351190

Voici mon exemple:

 #define NAVIGATION_BTN_MARGIN 5 @implementation NewNavigationBar - (void)layoutSubviews { [super layoutSubviews]; UINavigationItem *navigationItem = [self topItem]; UIView *subview = [[navigationItem rightBarButtonItem] customView]; if (subview) { CGRect subviewFrame = subview.frame; subviewFrame.origin.x = self.frame.size.width - subview.frame.size.width - NAVIGATION_BTN_MARGIN; subviewFrame.origin.y = (self.frame.size.height - subview.frame.size.height) / 2; [subview setFrame:subviewFrame]; } subview = [[navigationItem leftBarButtonItem] customView]; if (subview) { CGRect subviewFrame = subview.frame; subviewFrame.origin.x = NAVIGATION_BTN_MARGIN; subviewFrame.origin.y = (self.frame.size.height - subview.frame.size.height) / 2; [subview setFrame:subviewFrame]; } } @end 

J’espère que cela aide.

Essayez le code ci-dessous,

 UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:@"Logout" style:UIBarButtonItemStyleDone target:self action:nil]; [button setBackgroundVerticalPositionAdjustment:-20.0f forBarMesortingcs:UIBarMesortingcsDefault]; [[self navigationItem] setRightBarButtonItem:button]; 

C’est utilisé pour changer la position ‘y’ dans ce code. Changez la valeur ‘y’ (ici -20.0f) en fonction de vos besoins. Si la valeur est positive, la position du bouton diminuera. Si la valeur est négative, cela augmentera la position de votre bouton.

J’avais besoin de régler mon bouton pour qu’il soit plus à droite. Voici comment je l’ai fait en utilisant UIAppearance dans Swift. Il y a une propriété de position verticale là aussi donc j’imagine que vous pouvez ajuster dans n’importe quelle direction.

 UIBarButtonItem.appearance().setTitlePositionAdjustment(UIOffset.init(horizontal: 15, vertical: 0), forBarMesortingcs: UIBarMesortingcs.Default) 

Cela me semble beaucoup moins envahissant que de jouer directement avec le cadre ou d’append des sous-vues personnalisées.

Si vous utilisez simplement une image et non le chrome par défaut, vous pouvez utiliser des encarts d’image négatifs (définis dans l’inspecteur de taille) pour déplacer votre image dans l’UIBarButtonItem (pratique car par défaut, le remplissage horizontal peut entraîner à l’intérieur que vous voulez). Vous pouvez également utiliser les encarts d’image pour positionner l’image en dehors des limites de l’UIBarButtonItem, et tout le voisinage du bouton de gauche est taraudable, vous n’avez donc pas à vous soucier de le positionner près d’un touchez la cible. (au moins, dans des limites raisonnables)

La meilleure solution que je pourrais trouver consiste à initialiser un UIBarButtonItem avec une sous-vue qui inclut un espace supplémentaire à gauche / à droite. De cette façon, vous n’aurez pas à vous soucier du sous-classement et à la modification de la disposition des autres éléments de la barre de navigation, tels que le titre.

Par exemple, pour déplacer un bouton de 14 points vers la gauche:

 UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, image.size.width + 14, image.size.height)]; UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(-14, 0, image.size.width, image.size.height); [button setImage:image forState:UIControlStateNormal]; [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; [containerView addSubview:button]; UIButton* button2 = [UIButton buttonWithType:UIButtonTypeCustom]; button2.frame = CGRectMake(0, 0, image.size.width + 14, image.size.height); [button2 addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; [containerView addSubview:button2]; UIBarButtonItem* item = [[[self alloc] initWithCustomView:containerView] autorelease]; 

Comme l’a dit @Anomie, nous devons sous- UINavigationBar et remplacer layoutSubviews() .

Cela placera tous les éléments de bouton de la barre de droite fermement attachés sur le côté droit de la barre de navigation (par opposition à être légèrement ajusté à gauche par défaut) :

 class AdjustedNavigationBar: UINavigationBar { override func layoutSubviews() { super.layoutSubviews() if let rightItems = topItem?.rightBarButtonItems where rightItems.count > 1 { for i in 0.. 

Le seul endroit pour définir la propriété UINavigationBar de UINavigationController est son init (), comme ceci:

 let controllerVC = UINavigationController(navigationBarClass: AdjustedNavigationBar.self, toolbarClass: nil) controllerVC.viewControllers = [UIViewController()] 

La deuxième ligne définit le contrôleur de vue racine de UINavigationController. (Puisque nous ne pouvons pas le définir via init(rootViewController:)

Swift 3.1

 let cancelBarButtonItem = UIBarButtonItem() cancelBarButtonItem.setBackgroundVerticalPositionAdjustment(4, for: .default) vc.navigationItem.setLeftBarButton(cancelBarButtonItem, animated: true) 
  • Swift 3
  • hauteur de la barre de navigation personnalisée
  • pas de titre sautant

Étape 1: Définissez la position du titre à l’aide de l’API Apparence. Par exemple, dans le didFinishLaunchingWithOptions de AppDelegate

 UINavigationBar.appearance().setTitleVerticalPositionAdjustment(-7, for: .default) 

Étape 2: Sous classe UINavigationBar

 class YourNavigationBar: UINavigationBar { let YOUR_NAV_BAR_HEIGHT = 60 override func sizeThatFits(_ size: CGSize) -> CGSize { return CGSize(width: UIScreen.main.bounds.width, height: YOUR_NAV_BAR_HEIGHT) } override func layoutSubviews() { super.layoutSubviews() let navigationItem = self.topItem for subview in subviews { if subview == navigationItem?.leftBarButtonItem?.customView || subview == navigationItem?.rightBarButtonItem?.customView { subview.center = CGPoint(x: subview.center.x, y: YOUR_NAV_BAR_HEIGHT / 2) } } } } 

Voici la solution d’Adriano utilisant Swift 3. C’était la seule solution qui fonctionnait pour moi et j’en ai essayé plusieurs.

  let suggestImage = UIImage(named: "menu.png")! let suggestButton = UIButton(frame: CGRect(x:0, y:0, width:34, height:20)) suggestButton.setBackgroundImage(suggestImage, for: .normal) suggestButton.addTarget(self, action: #selector(self.showPopover(sender:)), for:.touchUpInside) suggestButton.transform = CGAffineTransform(translationX: 0, y: -8) // add the button to a container, otherwise the transform will be ignored let suggestButtonContainer = UIView(frame: suggestButton.frame) suggestButtonContainer.addSubview(suggestButton) let suggestButtonItem = UIBarButtonItem(customView: suggestButtonContainer) // add button shift to the side navigationItem.leftBarButtonItem = suggestButtonItem 

Dans mon cas

  1. changer le cadre de barbuttonItem pour personnaliser les espaces

  2. Ajouter, Supprimer barButtonItems dynamicment.

  3. changer les couleurs des teintes par contentOffset.y de tableview

comme ça entrer la description de l'image ici entrer la description de l'image ici

entrer la description de l'image ici entrer la description de l'image ici

Si votre cible minimale est iOS 11, vous pouvez modifier les frameworks barButton dans viewDidLayoutSubviews.

 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // Change the navigationBar item frames if let customView = wishButton.customView?.superview { customView.transform = CGAffineTransform(translationX: 7.0, y: 0) } if let customView = gourmetCountButton.customView?.superview { customView.transform = CGAffineTransform(translationX: 9.0, y: 0) } } 

Mais, il a seulement fonctionné sur iOS 11.

J’ai aussi essayé d’utiliser le FixedSpace. Mais cela n’a pas fonctionné dans plusieurs éléments de navigationBarButton.

  let space = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) space.width = -10 

J’ai donc modifié la largeur de CustomView pour ajuster l’espace horizontal.

Ceci est l’un de mes classe barButtonItem

 final class DetailShareBarButtonItem: UIBarButtonItem { // MARK: - Value // MARK: Public ***// Change the width to adjust space*** let button = UIButton(frame: CGRect(x: 0, y: 0, width: 32.0, height: 30.0)) override var tintColor: UIColor? { didSet { button.tintColor = tintColor } } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setButton() } required override init() { super.init() setButton() } // MARK: - Function // MARK: Private private func setButton() { // Button button.setImage( #imageLiteral(resourceName: "navibarIcShare02White").withRenderingMode(.alwaysTemplate), for: .normal) button.tintColor = .white button.imageEdgeInsets = UIEdgeInsetsMake(0, 1.0, 1.0, 0) button.imageView?.contentMode = .scaleAspectFill let containerView = UIView(frame: button.bounds) containerView.backgroundColor = .clear containerView.addSubview(button) customView = containerView } } 

C’est le résultat.

J’ai testé sur iOS 9 ~ 11, (Swift 4)

entrer la description de l'image ici

UIBarButtonItem avec une vue personnalisée et une surcharge layoutSubviews dans une vue personnalisée, comme ceci

 -(void) layoutSubviews { [super layoutSubviews]; CGRect frame = self.frame; CGFloat offsetY = 5; frame.origin.y = (44 - frame.size.height) / 2 - offsetY; self.frame = frame; } 

Vous pouvez toujours faire des ajustements en utilisant Insets sur le bouton. Par exemple,

 UIButton *toggleBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [toggleBtn setFrame:CGRectMake(0, 0, 20, 20)]; [toggleBtn addTarget:self action:@selector(toggleView) forControlEvents:UIControlEventTouchUpInside]; [toggleBtn setImageEdgeInsets:((IS_IPAD)? UIEdgeInsetsMake(0,-18, 0, 6) : UIEdgeInsetsMake(0, -3, 0, -3))]; UIBarButtonItem *toggleBtnItem = [[UIBarButtonItem alloc] initWithCustomView: toggleBtn]; self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:searchBtnItem, toggleBtnItem, nil]; 

Ça marche pour moi.

Voici une solution de contournement simple et suffisante pour mes besoins. J’ai ajouté un bouton d’information sur le côté droit de l’UINavigationBar mais, par défaut, il se trouve trop près du bord. En étendant la largeur du cadre, j’ai pu créer l’espacement supplémentaire nécessaire à droite.

  UIButton *info = [UIButton buttonWithType:UIButtonTypeInfoLight]; CGRect frame = info.frame; frame.size.width += 20; info.frame = frame; myNavigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]initWithCustomView:info]autorelease]; 

J’ai trouvé la solution à ce problème en effectuant des ajustements dans les encarts de bord d’image du bouton personnalisé. J’avais l’exigence dans l’application pour augmenter la hauteur de la barre de navigation et après avoir augmenté la hauteur rend le problème des images rightBarButtonItem et leftBarButtonItem images.

Trouvez le code ci-dessous: –

 UIImage *image = [[UIImage imageNamed:@"searchbar.png"]; UIButton* searchbutton = [UIButton buttonWithType:UIButtonTypeCustom]; [searchbutton addTarget:self action:@selector(searchBar:) forControlEvents:UIControlEventTouchUpInside]; searchbutton.frame = CGRectMake(0,0,22, 22); [searchbutton setImage:image forState:UIControlStateNormal]; [searchbutton setImageEdgeInsets:UIEdgeInsetsMake(-50, 0,50, 0)]; // Make BarButton Item UIBarButtonItem *navItem = [[UIBarButtonItem alloc] initWithCustomView:searchbutton]; self.navigationItem.rightBarButtonItem = navItem; 

J’espère que ça aide quelqu’un.