right custom bar uibutton uinavigationbar uibarbuttonitem ios7 uinavigationitem

uibutton - custom - UIBarButtonItem con vista personalizada no alineada correctamente en iOS 7 cuando se usa como elementos de barra de navegaciĆ³n izquierda o derecha



swift navigation bar add button (13)

El siguiente código funciona a través de iOS 6:

UIButton *myButton = nil; myButton = [UIButton buttonWithType:UIButtonTypeCustom]; myButton.bounds = CGRectMake(0,0,44,30); // setup myButton''s images, etc. UIBarButtonItem *item = nil; item = [[UIBarButtonItem alloc] initWithCustomView:customButton];

Así es como se supone que el botón está alineado:

Sin embargo, en iOS 7, el botón parece estar desplazado desde la derecha o la izquierda por demasiados píxeles:

¿Cómo puedo hacer que mis elementos de botón de barra personalizada estén alineados correctamente?


* Solución encontrada, lea al final de la respuesta. *

@jaredsinclair

Tengo un caso similar al de Kyle Begeman

Este es el botón

- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; } return self; } - (UIEdgeInsets)alignmentRectInsets { UIEdgeInsets insets; if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")){ if ([self isLeftButton]) { insets = UIEdgeInsetsMake(0, 9.0f, 0, 0); } else { insets = UIEdgeInsetsMake(0, 0, 0, 9.0f); } }else{ insets = UIEdgeInsetsZero; } return insets; } - (BOOL)isLeftButton { return self.frame.origin.x < (self.superview.frame.size.width / 2); }

y lo uso en este caso

PBNavigationBarButton *dashboardButton = [PBNavigationBarButton buttonWithType:UIButtonTypeCustom]; UIImage *dashboardImage = [UIImage imageNamed:@"btn_dashboard.png"]; UIImage *dashboardImageHighlighted = [UIImage imageNamed:@"btn_dashboard_pressed.png"]; NSInteger halfImageWidth = ceilf([dashboardImage size].width/2.0f); [dashboardButton setBackgroundImage:[dashboardImage stretchableImageWithLeftCapWidth:halfImageWidth topCapHeight:0] forState:UIControlStateNormal]; [dashboardButton setBackgroundImage:[dashboardImageHighlighted stretchableImageWithLeftCapWidth:halfImageWidth topCapHeight:0] forState:UIControlStateHighlighted]; [dashboardButton addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; [dashboardButton sizeToFit]; UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:dashboardButton];

Todo se ve muy bien, excepto que, cuando vuelvo al VC anterior, el botón se reposiciona. Como un pequeño salto. Para mí, salta de inmediato, no después de un segundo. Y sucede después de que hago el popVC desde NavigationViewController.

Editar: La respuesta a continuación, el método de Swizzling de Marius me ayudó también.


@jaredsinclair

Aquí hay un vistazo a mi código.

// Create the tweetly button that will show settings self.tweetlyDisplay = [NavButton buttonWithType:UIButtonTypeCustom]; [self.tweetlyDisplay setFrame:CGRectMake(0, 0, 90, 44)]; [self.tweetlyDisplay setBackgroundColor:[UIColor clearColor]]; [self.tweetlyDisplay setBackgroundImage:[UIImage imageNamed:@"settings.png"] forState:UIControlStateNormal]; [self.tweetlyDisplay setAdjustsImageWhenHighlighted:NO]; [self.tweetlyDisplay addTarget:self action:@selector(tweetlyPressed:) forControlEvents:UIControlEventTouchUpInside]; // Add the Tweetly button as the left bar button item // This had a glitch that moves the image to the right somewhat UIBarButtonItem *leftBarButton = [[UIBarButtonItem alloc] initWithCustomView:self.tweetlyDisplay]; self.navigationItem.leftBarButtonItem = leftBarButton;

¿Ves algo que no está bien?

Aquí está el resultado. La segunda imagen no es tan visible porque tuve que tomar el tiempo de la captura de pantalla y todavía está en transición, pero se puede ver claramente cómo se compensa incorrectamente.

Buena imagen normal:

Mala imagen de compensación:

Después de aproximadamente medio segundo, la imagen vuelve a la ubicación original de la imagen.

Aquí está mi código para NavButton.h y .m:

/********************************************** NavButton.h **********************************************/ #import <UIKit/UIKit.h> @interface NavButton : UIButton @end /********************************************** NavButton.m **********************************************/ #import "NavButton.h" @implementation NavButton { int imageHeight; } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code imageHeight = 44; } return self; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (UIEdgeInsets)alignmentRectInsets { UIEdgeInsets insets; if ([self isLeftButton]) { insets = UIEdgeInsetsMake(0, 9.0f, 0, 0); } else { // IF ITS A RIGHT BUTTON insets = UIEdgeInsetsMake(0, 0, 0, 9.0f); } return insets; } - (BOOL)isLeftButton { return self.frame.origin.x < (self.superview.frame.size.width / 2); } // THIS IS THE TRICK. We make the height of the background rect match the image. -(CGRect)backgroundRectForBounds:(CGRect)bounds { CGRect bgRect = bounds; bgRect.origin.y = (bounds.size.height - imageHeight)/2.0f; bgRect.size.height = imageHeight; return bgRect; } @end


Cambie lo siguiente para su UIButton

Control -> Alineación -> Horizontal para alinear a la derecha


Funciona hasta iOS11!

Puede usar espacios flexibles negativos y la propiedad rightBarButtonItems en lugar de rightBarButtonItem:

UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; spacer.width = -10; // for example shift right bar button to the right self.navigationItem.rightBarButtonItems = @[spacer, yourBarButton];


He intentado todas las respuestas anteriores y nada funcionó para mí. Y aquí está lo que funciona, si alguien necesita esto:

(No se necesitan subclases)

// Add your barButtonItem with custom image as the following UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleBordered target:self action:@selector(categoryButtonPressed)]; // set your custom image [barButton setImage:categoryImage]; // finally do the magic barButton.imageInsets = UIEdgeInsetsMake(0.0, -20, 0, 0);

- Eche un vistazo al resultado.

Observe el espacio al botón izquierdo y desde el botón derecho (el botón derecho tiene el comportamiento predeterminado)


Me gustaría agregar a @jaredsinclair confirmado la respuesta a los métodos de anulación a continuación para aquellos que tienen texto y / o imagen en su botón de navegación, de lo contrario el texto y la imagen no se alinearán (solo la imagen de fondo):

- (UIEdgeInsets) titleEdgeInsets { if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) { if (IF_ITS_A_LEFT_BUTTON) { { return UIEdgeInsetsMake(0, 0, 0, 9.0f); } else { // IF_ITS_A_RIGHT_BUTTON return UIEdgeInsetsMake(0, 9.0f, 0, 0); } } return [super titleEdgeInsets]; } - (UIEdgeInsets)imageEdgeInsets { if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) { if (IF_ITS_A_LEFT_BUTTON) { return UIEdgeInsetsMake(0, 0, 0, 9.0f); } else { // IF_ITS_A_RIGHT_BUTTON return UIEdgeInsetsMake(0, 9.0f, 0, 0); } } return [super imageEdgeInsets]; }

ps la macro es:

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)


No es un gran admirador de la subclase UIButton o el método swizzling de la respuesta de Marius: https://.com/a/19317105/287403

Acabo de usar un envoltorio simple y moví la x del marco del botón en una dirección negativa hasta que encontré la posición correcta. La pulsación de teclas también parece estar bien (aunque podría ampliar el ancho del botón para que coincida con el desplazamiento negativo si fuera necesario).

Aquí está el código que uso para generar un nuevo botón de retroceso:

- (UIBarButtonItem *) newBackButton { // a macro for the weak strong dance @weakify(self); UIButton *backButton = [[UIButton alloc] init]; [backButton setTitle:@"Back" forState:UIControlStateNormal]; backButton.titleLabel.font = [UIFont systemFontOfSize:17]; CGFloat width = [@"Back" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:17]} context:nil].size.width + 27; backButton.frame = CGRectMake(-17.5, 0, width + 17.5, 44); [backButton setImage:[UIImage imageNamed:@"UINavigationBarBackIndicatorDefault"] forState:UIControlStateNormal]; [backButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 14, 0, 0)]; [backButton setTitleColor:mTCOrangeColor forState:UIControlStateNormal]; backButton.contentEdgeInsets = UIEdgeInsetsZero; backButton.imageEdgeInsets = UIEdgeInsetsZero; [backButton addEventHandler:^(id sender) { // a macro for the weak strong dance @strongify(self); // do stuff here } forControlEvents:UIControlEventTouchUpInside]; UIView *buttonWrapper = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 44)]; [buttonWrapper addSubview:backButton]; return [[UIBarButtonItem alloc] initWithCustomView:buttonWrapper]; }


Ok, fui por la otra "dirección". Hice que todo se alineara correctamente a través de Storyboard con iOS 7 (suponiendo que así siga funcionando). Y luego, utilizando el enfoque describir subclase, subclase UIButton con la siguiente implementación.

- (UIEdgeInsets)alignmentRectInsets { UIEdgeInsets insets; if (SYSTEM_VERSION_LESS_THAN(@"7.0")) { if ([self isLeftButton]) { insets = UIEdgeInsetsMake(0, -10, 0, 0); } else { insets = UIEdgeInsetsMake(0, 0, 0, -10); } } else { insets = UIEdgeInsetsZero; } return insets; } - (BOOL)isLeftButton { return self.frame.origin.x < (self.superview.frame.size.width / 2); }

Por lo tanto, este código solo se ejecuta si el dispositivo es anterior a iOS 7.

Gracias por la información @jaredsinclair!


Para solucionar este error, debe subclase UIButton para que pueda anular alignmentRectInsets . A partir de mis pruebas, deberá devolver un UIEdgeInsets con un desplazamiento a la derecha positivo o un desplazamiento a la izquierda positivo, dependiendo de la posición del botón. Estos números no tienen sentido para mí (al menos uno de ellos debería ser negativo, de acuerdo con el sentido común), pero esto es lo que realmente funciona:

- (UIEdgeInsets)alignmentRectInsets { UIEdgeInsets insets; if (IF_ITS_A_LEFT_BUTTON) { insets = UIEdgeInsetsMake(0, 9.0f, 0, 0); } else { // IF_ITS_A_RIGHT_BUTTON insets = UIEdgeInsetsMake(0, 0, 0, 9.0f); } return insets; }

Un agradecimiento especial a @zev por sugerir que intente ajustar alignmentRectInsets.


Se me ocurrió una versión abreviada del enfoque de jaredsinclair:

- (UIEdgeInsets)alignmentRectInsets { return [self isLeftButton] ? UIEdgeInsetsMake(0, 9.0f, 0, 0) : UIEdgeInsetsMake(0, 0, 0, 9.0f); } - (BOOL)isLeftButton { return self.frame.origin.x < (self.superview.frame.size.width / 2); }

Funciona de maravilla.


Simplemente ajusta imageEdgeInsets para arreglar este error.

prueba esto.

UIButton *actionBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 40, 40)]; [actionBtn setImage:[UIImage imageNamed:@"arrow.png"] forState:UIControlStateNormal]; [actionBtn addTarget:self action:@selector(goToSetting) forControlEvents:UIControlEventTouchUpInside]; actionBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 9, 0, -9); UIBarButtonItem *profileBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:actionBtn]; self.topViewController.navigationItem.rightBarButtonItems = @[profileBarButtonItem];



en ios7 puedes simplemente agregar un barbuttonitem ficticio para fijar el espacio izquierdo, debes agregar el maniquí como el primero, para el derecho como el último

ejemplo para la izquierda, debe agregar esto después de configurar sus elementos originales o en viewdidload si está configurando botones usando el guión gráfico.

NSMutableArray *buttons = [[NSMutableArray alloc] init]; UIBarButtonItem *spacerItem = [[UIBarButtonItem alloc] init]; [buttons addObject:spacerItem]; for(UIBarButtonItem *item in self.leftBarButtonItems){ [buttons addObject:item]; } [self setLeftBarButtonItems:[NSArray arrayWithArray:buttons] animated:NO];