Cambiar la posición de UIBarButtonItem en UINavigationBar

¿Cómo puedo cambiar la posición de un UIBarButtonItem en un UINavigationBar? Me gustaría que mi botón sea aproximadamente 5px más alto que su posición normal.

No hay una forma particularmente buena de hacer esto. Su mejor opción si realmente debe es subclasificar UINavigationBar, y anular layoutSubviews para llamar a [super layoutSubviews] y luego buscar y reposicionar la vista del botón.

Este código crea un botón Atrás para UINavigationBar con fondo de imagen y posición personalizada. El truco es crear una vista intermedia y modificar sus límites.

 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; 

Lo solucioné usando la transformación y la vista personalizada:

(Rápido)

  // 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 

Para aquellos de ustedes en desarrollo para iOS 5 que tropezaron con esto y se desanimaron … Pruebe algo como esto:

 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 forBarMetrics:UIBarMetricsDefault]; 

La mejor manera es subclasificar su UINavigationBar, como se describe aquí: https://stackoverflow.com/a/17434530/1351190

Aquí está mi ejemplo:

 #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 

Espero eso ayude.

Pruebe el código a continuación,

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

Se usa para cambiar la posición ‘y’ en este código. Cambie el valor ‘y’ (aquí es -20.0f) según su requisito. Si el valor es positivo, bajará la posición del botón. Si el valor es negativo, boostá la posición de tu botón.

Necesitaba configurar mi botón para que fuera más hacia la derecha. Así es como lo hice usando UIAppearance en Swift. También hay una posición de posición vertical allí, así que imagino que puedes ajustar en cualquier dirección.

 UIBarButtonItem.appearance().setTitlePositionAdjustment(UIOffset.init(horizontal: 15, vertical: 0), forBarMetrics: UIBarMetrics.Default) 

Esto me parece mucho menos invasivo que jugar con el marco directamente o agregar subvistas personalizadas.

Si simplemente está usando una imagen y NO el cromo predeterminado, puede usar imágenes negativas (configuradas en el inspector de tamaño) para mover su imagen dentro del UIBarButtonItem (útil porque de manera predeterminada el relleno horizontal puede hacer que la imagen sea más hacia el interior de lo que quieras). También puede usar las inserciones de imagen para colocar la imagen fuera de los límites del UIBarButtonItem, y se puede tocar toda la zona del botón del lado izquierdo, por lo que no tiene que preocuparse por asegurarse de que esté cerca de un toca el objective (al menos, dentro de lo razonable)

La mejor solución que pude encontrar es inicializar un UIBarButtonItem con una subvista que incluye espacio adicional a la izquierda / derecha. De esta forma, no tendrá que preocuparse por la creación de subclases y cambiar el diseño de otros elementos dentro de la barra de navegación, como el título.

Por ejemplo, para mover un botón 14 puntos hacia la izquierda:

 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]; 

Como dijo @Anomie, debemos UINavigationBar , y anular layoutSubviews() .

Esto colocará todos los elementos del botón de barra correctamente unidos al lado derecho de la barra de navegación (en lugar de estar ligeramente ajustados a la izquierda por defecto) :

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

El único lugar para establecer la propiedad UINavigationBar de UINavigationController está en su init (), así:

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

La segunda línea establece el controlador de vista raíz de UINavigationController. (Dado que no podemos configurarlo a través de init(rootViewController:)

Swift 3.1

 let cancelBarButtonItem = UIBarButtonItem() cancelBarButtonItem.setBackgroundVerticalPositionAdjustment(4, for: .default) vc.navigationItem.setLeftBarButton(cancelBarButtonItem, animated: true) 
  • Swift 3
  • altura de la barra de navegación personalizada
  • sin título saltando

Paso 1: establece la posición del título usando la API de apariencia. Por ejemplo, en AppDelegate’s FinishLaunchingWithOptions

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

Paso 2: Subclase 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) } } } } 

Aquí está la solución de Adriano usando Swift 3. Fue la única solución que funcionó para mí y probé varias.

  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 

En mi caso

  1. cambie el marco de barbuttonItem para personalizar espacios

  2. Agregar, eliminar barButtonItems dinámicamente.

  3. cambiar los colores del tinte por contentOffset.y de tableview

Me gusta esto enter image description here enter image description here

enter image description here enter image description here

Si su objective mínimo es iOS 11, puede cambiar los marcos barButton en 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) } } 

Pero, solo funcionó en iOS 11.

También intenté usar el fixedSpace. Pero no funcionó en múltiples elementos de navigationBarButton.

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

Entonces, cambié el ancho de customView para ajustar el espacio horizontal.

Esta es una de las clases my 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 } } 

Este es el resultado.

Probé en iOS 9 ~ 11, (Swift 4)

enter image description here

Init UIBarButtonItem con vista personalizada y layoutSubviews sobrecarga. layoutSubviews en vista personalizada, como esta.

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

Siempre puede hacer ajustes usando Insets en el botón. Por ejemplo,

 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]; 

Esto funciona para mi.

Aquí hay una solución simple que fue suficiente para mis necesidades. Agregué un botón de información en el lado derecho de UINavigationBar, pero de manera predeterminada se encuentra demasiado cerca del borde. Al ampliar el ancho del marco, pude crear el espaciado adicional necesario a la derecha.

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

Encontré la solución de este problema haciendo ajustes en los Incestos de Borde de Imagen del botón personalizado. Tuve el requisito en la aplicación para boost la altura de la barra de navegación y después de boost la altura hace que las imágenes de RightBarButtonItem y leftBarButtonItem tengan un problema sin posicionar.

Encuentra el código a continuación: –

 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; 

Espero que esto ayude a cualquiera.