UINavigationBar的drawRect在iOS 5.0中不被调用

我已经overrided(放在类别中,或调整)UINavigationBar的drawRect来显示自定义背景。 在iOS 5中,它不工作。 我该怎么办?

为UINavigationBar设置自定义背景以支持iOS5和iOS4!

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/


如你所知,在iOS 5出来之前,我们在AppDelegate使用了drawRect override来自定义UINavigationBar 。 但是要知道,iOS 5为我们提供了一些新的样式devise方法(旧的方法不起作用)。

如何构build可在iOS 4和iOS 5上使用程式化UINavigationBar

你必须这样做!

AppDelegate使用这个代码:

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

和iOS5的viewDidLoad方法(在你的视图实现中):

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

如果你看到,在这里我们问是否navbar将respondToSelector,以避免iOS4的崩溃!

这是一个不太好看的解决scheme,适用于iOS4和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 

尝试阅读iOS 5.0发行说明

在iOS 5中,UINavigationBar,UIToolbar和UITabBar实现已更改,因此drawRect:方法不会被调用,除非它在子类中实现。 重新实现了drawRect的应用程序:在任何这些类的类别中都会发现不调用drawRect:方法。 UIKit会执行链接检查,以防止在iOS 5之前链接的应用程序中调用该方法,但不支持iOS 5或更高版本中的此devise。

有一些可能的解决scheme:

最快的解决scheme对于我们最懒惰的人:

 @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 

再次。 它有效,但你不应该这样做。

另一种方式,如WWDC'11所示,重写UINavigationBar(Create MyNavigationBar)并像这样从xib初始化UINavigationController:

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

最后,为iOS5.0和iOS5.0使用逻辑stream程切换 – 在可能的地方使用新的API。

分类是错误的path,Swizzling是错误的path。 (他们只是在耳边低声说:“给自己一个黑暗的一面,这是保存你的应用程序的唯一方法。”)

 @implementation UINavigationBar (MyCustomNavBar) - (void)setBackgroudImage:(UIImage*)image { CGSize imageSize = [image size]; self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, imageSize.height); UIImageView *backgroundImage = [[UIImageView alloc] initWithImage:image]; backgroundImage.frame = self.bounds; [self addSubview:backgroundImage]; [backgroundImage release]; } @end 

上面的swizzling将允许你为UINavigationBar(iOS5和iOS4)设置任何自定义的背景图片。

按照此链接 ,使您的代码与iOS4,5和6兼容。

您只需在Photoshop或其他软件中制作一个尺寸为320×44或640×88的矩形(用于视网膜显示)并将其导入到您的项目中

在AppDelegate中使用这个代码(在#import和@implementation AppDelegate之间的头文件中):

 @implementation UINavigationBar (CustomImage) - (void)drawRect:(CGRect)rect { UIImage *image = [UIImage imageNamed:@"top_bar.png"]; [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; } @end 

在viewDidLoad中为iOS5和iOS6使用这个代码:

 #if defined(__IPHONE_5_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0 if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){ [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"top_bar.png"] forBarMetrics:UIBarMetricsDefault]; } #endif 

在iOS 5之后- (void)drawRect:(CGRect)rect在我们为UINavigationBar创build类别时不会调用- (void)drawRect:(CGRect)rect ,但是可以调用-(void)awakeFromNib并添加所有要添加的代码。