UINavigationBar详细指南

1.UINavigationBar和UINavigationItem

UINavigationItem : NSObject

When building a navigation interface, each view controller pushed onto the 
navigation stack must have a `UINavigationItem` object that contains the 
buttons and views it wants displayed in the navigation bar. The 
managing UINavigationController object uses the navigation items of the 
topmost two view controllers to populate the navigation bar with content.

当view controller push进入navigation stack的时候,UINavigationItem是必须存在的,通常navigationController已经自动创建了UINavigationItem,它负责管理UInavigationController中的item和Title的内容以及交互。

UINavigationBar :UIView<UIBarPositioning>

A UINavigationBar object is a bar, typically displayed at the top of the 
window, containing buttons for navigating within a hierarchy of screens. 
The primary components are a left (back) button, a center title, and an 
optional right button. You can use a navigation bar as a standalone object or 
in conjunction with a navigation controller object.

A navigation bar is most commonly used within a navigation controller. 
The object creates, displays, and manages its 
associated navigation bar, and uses attributes of the view controllers you 
add to control the content displayed in the navigation bar.

If you use a navigation controller to manage the navigation between 
different screens of content, the navigation controller creates a navigation 
bar automatically and pushes and pops navigation items when appropriate.

图片.png

通常情况下我们使用UInavigationController push或者pop一个viewController的时候,UINavigationBar会被自动的创建,UINavigationBar是一个View的子类,我们可以自定义其显示的样式,包括title字体,背景,颜色等。

关系

A navigation controller uses the navigationItem property 
on UIViewController to provide the model objects to its navigation bar when 
navigating a stack of view controllers. The default navigation item uses the 
view controller’s title, but you can override the navigationItem on 
a UIViewController subclass to gain complete control 
of the navigation bar’s content.

UINavigationBar的内容通常是由navigationItem提供,包括title和items等,如果想自定义UINavigationBar中的内容,那么需要更改navigationItem的配置。

2.UINavigationBar

UIBarStyle默认有4中样式,translucent属性设置bar是否透明。
Bar默认带有毛玻璃效果。

typedef enum UIBarStyle : NSInteger {
    UIBarStyleDefault = 0,
    UIBarStyleBlack = 1,
    UIBarStyleBlackOpaque = 1,
    UIBarStyleBlackTranslucent = 2
} UIBarStyle;

UINavigationBar可以自定义的属性

Core Attributes : Style , Bar Tint , Shadow Image, Back Image, Back Mask.
Attribute: Title Font, Title Color, Title Shadow.

tip:去除UINavigationBar下方横线

[self.navigationBar setShadowImage:[[UIImage alloc] init]];
/* 全局 */
[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
/* 另外一种方式 */
self.navigationController.navigationBar.clipsToBounds = YES; 

3.UINavigationItem

UINavigationItem提供了API设置leftItems,titleView,rightItems 和BackItems的方法。

3.1 backBarButtonItem

When this navigation item is immediately below the top item in the stack, 
the navigation controller derives the back button for the navigation bar from 
this navigation item. When this property is `nil`, the navigation item uses 
the value in its title property to create an appropriate back button. If you 
want to specify a custom image or title for the back button, you can assign a 
custom bar button item (with your custom title or image) to this property 
instead. When configuring your bar button item, do not assign a custom 
view to it; the navigation item ignores custom views in the back bar button 
anyway.

backBarButtonItem在UINavigationController中push时候自动的添加,如果你没有指定title,则返回按钮中的文字默认是前一个view controller的title。
不要尝试去添加custom view,因为不会生效。
hidesBackButton设置为YES可以隐藏返回按钮,默认是NO。

The backBarButtonItem property of a navigation item reflects the back 
button you want displayed when the current view controller is just below the 
topmost view controller. In other words, the back button is not used when 
the current view controller is topmost.

If the title of your back button is too long to fit in the available space on the 
navigation bar, the navigation bar may substitute the string “Back” in place 
of the button’s original title. The navigation bar does this only if the back 
button is provided by the previous view controller. If the new top-level view 
controller has a custom left bar button item—an object in the 
leftBarButtonItems or BarButtonItem property of its navigation item—the navigation bar does not change the button title.


你在当前View controller中设置的backBarButtonItem并不是当前view中backBarButtonItem的样式,而是从当前view controller中push出的view controller中backBarButtonItem的样式,topmost view controller中backBarButtonItem是无效的。
换而言之,当你准备push一个view controller并想自定义这个view controller的backBarButtonItem,那么在push之前,就需要设置好backBarButtonItem的样式。

UIViewController *nextViewController = [[UIViewController alloc] initWithNibName:@"" bundle:nil];
//设置nextViewController中navigationbar的backBtn样式。
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"navBacklIcon"] style:UIBarButtonItemStylePlain target:self action:@selector(Navback)];
[self showViewController:nextViewController sender:nil];

backBarButtonItem的title如果过长则会显示"back"。
如果设置了leftBarButtonItem,则backBarButtonItem将不会显示,除非将leftItemsSupplementBackButton设置为YES,默认为NO。
你可以用leftBarButtonItem替代backBarButtonItem,但是backBarButtonItem和leftBarButtonItem的位置是有差异的。

3.自定义UINavigationController

通常一个项目NavigationBar的风格都是统一的,我们可以通过下面方法来设置全局样式.

[[UINavigationBar appearance] setShadowImage:[[UIImage alloc] init]];
[[UINavigationBar appearance] set........

但是一个更好的方法是自定义一个UINavigationController。

@interface Q_navigationController ()<UINavigationControllerDelegate,UIGestureRecognizerDelegate>
@end

@implementation Q_navigationController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self configNavBar];
}
-(void)configNavBar{//全局样式
    [self.navigationBar setShadowImage:[[UIImage alloc] init]];
    self.navigationBar.translucent = NO;
    self.navigationBar.titleTextAttributes = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:17],
                                               NSKernAttributeName:[NSNumber numberWithInteger:2],
                                               NSForegroundColorAttributeName:[UIColor colorWithRed:18.0/255 green:150.0/255 blue:219.0/255 alpha:1]
                                               };
    self.navigationBar.tintColor = [UIColor colorWithRed:18.0/255 green:150.0/255 blue:219.0/255 alpha:1];
}
@end

UINavigationControllerDelegate是UINavigationController的回调,我们可以在push和pop的时候收到回调,自定义一些需要的事情,比如设置自定义返回按钮。

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    if (navigationController.viewControllers.count > 1) {
        viewController.navigationItem.leftBarButtonItem = self.navBackBtn;
    }
}
-(UIBarButtonItem *)navBackBtn{
    if(!_navBackBtn){
        _navBackBtn =[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"navBacklIcon"] style:UIBarButtonItemStylePlain target:self action:@selector(Navback)];
    }
    return _navBackBtn;
}

自定义的UINavigationController也会带来一些问题,比如边缘返回的手势失效了,为了能让它正常的工作,我们还需要做一些工作,在需要它的时候将其enabled设置为YES。

- (void)viewDidLoad {
    [super viewDidLoad];
    [self configNavBar];
    
    self.delegate = self;
    self.interactivePopGestureRecognizer.delegate = self;
}

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    if (navigationController.viewControllers.count <= 1) {
        self.interactivePopGestureRecognizer.enabled = NO;
    }else{
        self.interactivePopGestureRecognizer.enabled = YES;
    }
}

但是interactivePopGestureRecognizer可能会引入一些手势冲突问题,比如https://www.jianshu.com/p/ffde99688cff中描述的那样。

总结

理解UINavigationBar和UINavigationItem的关系,这让我们更加优雅的设计代码去配置项目中导航栏。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容