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;
网友评论