View on GitHub

Bannings的博客

[iOS developer:@"不能过目不忘,故撰文以记之"];

定制UINavigationBar

ios   

在开发中经常需要定制某些界面,navigationController的navigationBar就是一个很典型的例子,比如要修改背景图、后退按钮等等。

背景图的修改很简单,但是需要了解iOS的框架,假设我给自己定制的UINavigationController增加一个接口用于修改背景图:

@property (nonatomic, retain) UIImage *backgroundImage;
那么该消息的实现如下:

-(void)setBackgroundImage:(UIImage *)backgroundImage{
    if ([self.navigationBar respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]) {
        [self.navigationBar setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];
        return;
    }
    self.navigationBar.layer.contents = (id)backgroundImage.CGImage;
}

iOS 5增加了大量API,可以基本满足我们的定制需求,所以如果是iOS 5,我们直接调5的API就行了,而最后一行代码是针对5以下的,也就是说这一行代码就可以修改了,写起来容易但是要知道为什么。众所周知一个视图如何显示是取决于它的drawRect方法,因为调这个方法之前iOS也不知道如何显示它,但其实drawRect方法的目的也是画图(显示内容),而且我们如果以其他的方式给出了内容(图)的话,drawRect方法就不会被调用了。

注:实际上UIView是CALayer的delegate,如果CALayer没有内容的话,会回调给UIView的displayLayer:或者drawLayer:inContext:方法,UIView在其中调用drawRect,draw完后的图会缓存起来,除非使用setNeedsDisplay或是一些必要情况,否则都是使用缓存的图。

虽然往navigationBar里面插入一个imageView也能达到这种目的,但是要麻烦得多,因为你要自己管理navigationBar的视图层级,原因在于iOS 4和iOS 5的版本不同,往navigationBar插入视图的位置是相反的,不处理的话会导致部份子视图被遮住。

-----------------------------------------猥琐的分界线-----------------------------------------

如果只想更改后退按钮的标准属性,比如title、target、action,那么就:

    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] init];
    backButtonItem.title = @"已改的";
    backButtonItem.target = self;
    backButtonItem.action = @selector(back);
    self.navigationItem.backBarButtonItem = backButtonItem;
    [backButtonItem release];
只要注意一点,这个设置是针对于子导航层级的,也就是你push到下个视图控制器的时候才会看到。

如果是想更改字体、颜色、背景之类的,就要用到UIButton了:

    UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom];
    [back setTitle:@"已改" forState:UIControlStateNormal];
    [back setFrame:CGRectMake(0, 0, 100, 32)];
    [back setBackgroundColor:[UIColor redColor]];
    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:back];
    self.navigationItem.leftBarButtonItem = backButtonItem;
    [backButtonItem release];
完全当成一个button来用,注意和上面的不同:赋给了leftBarButtonItem

如果你不知道何时添加这个自己的后退按钮?很简单,判断navigationBar.backItem有没有就行了,跟着系统走是不会错的,不过可能要再判断一下当前显示的viewController有没有用到leftBarButtonItem,不要覆盖掉逻辑就行了。


-----------------------------------------如有问题,请指出-----------------------------------------