UINavigationController详解

1 概述

UINavigationController继承自UIViewController,是一个基于栈的容器型控制器。既然是容器,它就能装一些东西,比如UIView能装各种组件(UILabel,UIButton等),UINavigationController装的是视图控制器。

一个UINavigationController包含了几个部分,

  • Navigation Stack导航栈,它以栈的形式来管理视图控制器。栈的一个视图控制器(栈底),称为根视图控制器,其他称为子视图控制器。栈中的控制器可以通过self.navigationController找到UINavigationController的实例。

  • UINavigationBar导航条,栈中的视图控制默认会在顶部加一个导航条,虽然Navigation Bar显示在子视图控制器的界面上,但是它是由UINavigationController实例管理的,不过,导航条的内容却是由子视图控制器决定(通过self.navigationItem设置)。

  • UIToolbar工具栏,UINavigationController在子视图的底部提供了工具栏,默认不显示,也很少用到。

2 Navigation Stack导航栈

UINavigationController的作用是以栈的方式管理UIViewController,所以方法基本上是围绕进出栈的。

  • 进栈方法

    当子视图控制器拿到UINavigationController的实例引用后,使用下列方法推控制器进栈:

    - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
    

    上面的进栈方法是最常用的,它将当个viewController推入栈中,如果要一次性设置多个viewController进栈,可以使用下面的方法:

    - (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated
    

    因为UINavigationController在一个时刻只能显示一个视图控制器,当设置了多个viewController时,显示栈顶的视图控制器。

  • 出栈方法

    - (UIViewController *)popViewControllerAnimated:(BOOL)animated; 
    - (NSArray<UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
    - (NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated; 
    

    UINavigationController有3中出栈方式,第一个是移除当前的子视图控制器,第二个是返回到指定的子视图控制器,UINavigationController会移除目标控制到栈顶之前的所有视图控制器。第三个是返回到栈底(根视图控制器)。

3 导航栏显示与隐藏

导航栏显示与否是UINavigationController控制的,NavigationController提供了如下方法显示与隐藏导航栏。

- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated; 

4 UINavationBar 导航条

导航条比较特别,它的创建,配置和显示是由UINaviagtionController负责的,而内容是由子视图控制器提供的,具体是navigationItem。

4.1 导航条内容定制

导航条的内容是由当前子视图控制器的navigationItem属性确定的,内容主要分为左边项,标题项以及右边项。

4.1.1 左边按钮定制

除了根视图控制器,在栈中的其他子视图控制器中,导航条的左边存在一个返回按钮,定制这个按钮的规则如下:

  • 如果当前栈顶的视图控制器定义了navigationItem.leftBarButtonItem属性,则以当前定义的为准。
  • 否则,如果上一个视图控制器定义了navigationItem.backBarButtonItem属性,则以上一个视图控制器定义的为准
  • 如果当前视图控制器为定义leftBarButtonItem属性,上一个视图控制器也没有定义backBarButtonItem。则以上一个视图控制器的title属性为准

navigationItem还有一个属性是leftBarButtonItems,它允许用户定义一个按钮集合放在导航条的左边。

4.1.2 标题定制

UINavigationController根据下面的顺序更新导航栏的标题项:

  • 栈顶视图控制器使用navigationItem.titleView自定义标题时,优先使用titleView
  • 否则,导航栏标题使用一个UILabel作为标题,内容从视图控制器的title属性中获取。

titleView是UIView的实例,也就是说标题可以是任意UIView的子类,上面的UILabel也是UIView的子类。

4.1.3 右边按钮定制

栈顶视图控制器设置了navigationItem.rightBarButtonItem时,UINavigationController会将其设置内容更新在导航栏的右边,如果没有设置,则在导航栏的右边不显示任何内容。

leftBarButtonItem、rightBarButtonItem以及backBarButtonItem都是UIBarButtonItem类型的。也就是说,如果我们要在导航条上定义按钮,就得使用UIBarButtonItem对象,如果系统提供的UIBarButtonItem的属性满足不了我们的需求,可以使用UIBarButtonItem.customView属性来包裹我们指定的视图。

4.2 导航栏的外观定制

导航栏的外观定制有两种方式,一种是通过navigationBar的实例定制,另一种是通过UIAppearance来获取实例类的外观代理对象定制外观,UIAppearance是一个协议(Protocol),实现了这个协议的类可以通过它的appearance方法获取这个类的外观代理,UIView已经实现了这个协议。通过UIAppearance外观代理类设置的外观是全局性的。

4.2.1 BarStyle导航条样式

导航栏默认有两种标准的显示样式:白底黑字和黑底白字,可以通过navigationBar.barStyle属性设置。

//把app中的所有导航条都设置为黑底白字
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];

//把myNavController下的导航条设置为黑底白字的样式,其他navigationController中的不会改变
[myNavController.navigationBar setBarStyle:UIBarStyleBlack]

4.2.2 translucent 透明度

导航条默认是半透明的(translucent),可以设置起为不透明,

[[UINavigationBar appearance] setTranslucent:NO];

需要注意的是,translucent=YES时,子视图控制器的self.view的原点在整个屏幕中的位置是导航栏的左上方(这个好理解,因为导航栏是透明的,有点像css的绝对定位,所以控制器的view会顶上去,那么原点的位置就发送了变化),当translucent=NO时,控制器的self.view的原点在屏幕中的位置在导航栏的左下方。

当translucent=YES时,可设置控制器的edgesForExtendedLayout属性来改变view的原点在屏幕中的位置

//从navigationBar下面开始计算一直到屏幕tabBar上部
self.edgesForExtendedLayout = UIRectEdgeNone;
//从屏幕边缘计算(默认)
self.edgesForExtendedLayout = UIRectEdgeAll; 
//navigationBar下面开始计算一直到屏幕tabBar上部
self.edgesForExtendedLayout = UIRectEdgeTop;
//从navigationBar下面开始计算一直到屏幕底部
self.edgesForExtendedLayout = UIRectEdgeBottom;

4.2.3 导航栏的字体与颜色

导航栏的字体与颜色分别由以下几个属性控制:

导航栏字体与颜色
  • barTintColor 导航栏背景色,前面我们说了,barStyle有两种样式白底和黑底,如果设置了barTintColor的值,这个值会覆盖barStyle设置的背景色。

    //设置导航栏的背景色
    [[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
    
  • tintColor 按钮颜色

    //按钮颜色
    [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
    
  • titleTextAtrributes 标题的样式,通过NSAttributedStringKey查看可设置的属性

     NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:[UIColor blackColor],
                            NSForegroundColorAttributeName,
                            [UIFont boldSystemFontOfSize:18.0],
                            NSFontAttributeName,nil];
     [UINavigationBar appearance].titleTextAttributes = dic;
    

4.2.4 导航栏透明

是导航栏完全透明可以设置背景图片和阴影图片两个属性。按照业务需求,一般只有个别的页面要求导航栏透明,所以这不使用全局设置,而在具体的ViewController中设置

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