No se llama a drawRect de UINavigationBar en iOS 5.0

He sobrescrito (puesto en categoría, o swizzled) UINavigationBar’s drawRect para mostrar fondo personalizado. En iOS 5 no funciona. ¿Que debería hacer?

¡Configurando fondo personalizado para UINavigationBar para soportar iOS5 e iOS4 también!

http://www.mladjanantic.com/setting-custom-background-for-uinavigationbar-what-will-work-on-ios5-and-ios4-too/

http://rogchap.com/2011/06/21/custom-navigation-bar-background-and-custom-buttons/


Como saben, hasta que salió el iOS 5, usamos drawRect override en AppDelegate para personalizar UINavigationBar . Pero sepa, iOS 5 nos da un nuevo método para el diseño (y el viejo no funciona).

¿Cómo construir una aplicación que funcione en iOS 4 e iOS 5 con UINavigationBar estilizada?

¡Debes hacer ambas cosas!

En AppDelegate usa este código:

 @implementation UINavigationBar (UINavigationBarCategory) - (void)drawRect:(CGRect)rect { UIImage *img = [UIImage imageNamed:@"navbar.png"]; [img drawInRect:rect]; } @end 

y en el método viewDidLoad para iOS5 (en su implementación de vista):

 if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){ [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"navbar.png"] forBarMetrics:UIBarMetricsDefault]; } 

Si lo ve, aquí estamos preguntando si navbar responderá a Selector para evitar el locking en iOS4.

Aquí hay una solución menos fea que funciona tanto para iOS4 como para 5:

 @implementation UINavigationBar (CustomBackground) - (UIImage *)barBackground { return [UIImage imageNamed:@"top-navigation-bar.png"]; } - (void)didMoveToSuperview { //iOS5 only if ([self respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]) { [self setBackgroundImage:[self barBackground] forBarMetrics:UIBarMetricsDefault]; } } //this doesn't work on iOS5 but is needed for iOS4 and earlier - (void)drawRect:(CGRect)rect { //draw image [[self barBackground] drawInRect:rect]; } @end 

Intenta leer las notas de la versión iOS 5.0

En iOS 5, las implementaciones UINavigationBar, UIToolbar y UITabBar han cambiado para que no se invoque el método drawRect: a menos que se implemente en una subclase. Las aplicaciones que han reimplementado drawRect: en una categoría en cualquiera de estas clases encontrarán que el método drawRect: no se llama. UIKit realiza la comprobación de enlaces para evitar que se llame al método en las aplicaciones vinculadas antes de iOS 5, pero no admite este diseño en iOS 5 o posterior.

Hay algunas soluciones posibles:

La solución más rápida para los más flojos:

 @interface MyNavigationBar : UINavigationBar @end @implementation MyNavigationBar - (void)drawRect:(CGRect)rect { } @end @implementation UINavigationBar (BecauseIMLazyHacks) /* Another Ugly hack for iOS 5.0 support */ + (Class)class { return NSClassFromString(@"MyNavigationBar"); } -(void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextTranslateCTM(context, 0, self.frame.size.height); CGContextScaleCTM(context, 1.0, -1.0); CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), barBackground.CGImage); } @end 

De nuevo. Funciona, pero no deberías hacerlo así.

Otra forma, como se sugiere en WWDC’11 es anular UINavigationBar (Create MyNavigationBar) e inicializar UINavigationController desde xib como aquí:

http://www.iosdevnotes.com/2011/09/custom-uinavigationbars-techniques/

Y, por último, use el interruptor de flujo lógico para iOS5.0 e iOS5.0. Use la API nueva donde sea posible.

Categorías es un camino equivocado, Swizzling es un camino equivocado. (Simplemente le susurran al oído: “Regálate el lado oscuro. Es la única forma en que puedes guardar tus aplicaciones”).