UINavigationController
-
UINavigationController继承自UIViewController,用来展示具有明显的层级结构的内容,让我们更高效的将层级结构的内容展现给用户。在每个层级中用一个UIViewController来展示具体内容。下面的图是iOS设备中的设置界面的图:
iOS设备的设置
UINavigationController是一个容器视图控制器,其内部展示着多个UIViewController的内容。UINavigationController的View由三个部分组成,最上面的UINavigationBar,最下面默认隐藏的toolbar,以及中间部分的UIViewController的View。
UINavigationController的层级结构
UINavigationController的堆栈管理
-
UINavigationController通过其管理的一个UIViewController堆栈来决定中间的View显示什么。中间的View显示的是UIViewController堆栈顶部的UIViewController的View。
UINavigationController - 理解上面这幅图很重要。我们看到UINavigationController拥有viewControllers,navigationBar,toolBar这些属性。其中viewControllers是一个数组,在这个数组中以堆栈的形式存放着多个UIViewController。堆栈是先进后出的原则。UINavigationController的中间的View显示的是位于堆栈顶部的UIViewController的View。
- 位于堆栈最底部的UIViewController我们称之为rootViewController(根视图控制器),一个UINavigationController的UIViewController堆栈中至少有一个视图控制器,也可以说一定存在根视图控制器。我们可以创建一个UIViewController,然后使用系统提供的方法让这个UIViewController进栈,也可以使用系统提供的方法让UIViewController堆栈中的视图控制器出栈。
UINavigationController的创建
创建UINavigationController的方法:
//创建一个视图控制器
FirstPageViewController *VC = [[FirstPageViewController alloc] init];
//把上面创建的视图控制器作为根视图控制器创建一个UINavigationController
//这样UINavigationController的UIViewController堆栈中已经有了一个视图控制器即VC,这时候UINavigationController的中间那部分的View显示的是VC的View。
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:VC];
当我们想要进入这个UINavigationController的页面时可以:
[self presentViewController:navigationController animated:YES completion:^{}];
UIViewController的进栈和出栈
- 进栈:
[self.navigationController pushViewController:VC animated:YES];
示例代码:
//我们有一个继承自UIViewController的类SecondPageViewController,创建该类的实例VC
SecondPageViewController *VC = [[SecondPageViewController alloc] init];
//然后我们使用系统的方法pushViewController:animated:使VC进入navigationController的UIViewController堆栈。
//此时这个堆栈中的栈顶元素变成了VC,因此navigationController的View部分展示的内容就变成了VC的View,所以画面进行了切换
[self.navigationController pushViewController:VC animated:YES];
- 出栈
- 使UIViewController中最顶层的元素出栈
[self.navigationController popViewControllerAnimated:YES];
执行这句话后,UIViewController中最顶层的元素出栈,所以堆栈中处于栈顶的元素发生了变化,navigationController中间的View也发生了变化,直观感觉就是退回了上一个页面。但是当堆栈中的元素只有一个时该方法无效,因为该堆栈中必须要保证至少要有一个元素。 - pop到指定的元素
假设现在UIViewController堆栈中有四个元素,从栈底到栈顶依次是VC1,VC2,VC3,VC4。我们现在正处在VC4的View中。那么现在我们想直接退到VC2的页面,可以这样做:
[self.navigationController popToViewController:self.navigationController.viewControllers[1] animated:YES];
这个方法实际上是使堆栈中这个指定的viewcontroller上面的元素全部出栈,这样这个指定的viewcontroller就成了栈顶元素,直观感觉是回退到了这个视图控制器的页面。
- 直接pop到根视图控制器
这个其实和上面的道理是一样的,就是使除栈底之外的其它视图控制器全部出栈,这样栈底的根视图控制器也是栈顶元素了。
[self.navigationController popToRootViewControllerAnimated:YES];
UINavigationBar
- UINavigationBar是UINavigationController的View的上面的那部分。UINavigationController负责创建UINavigationBar。而UINavigationBar的内容则是由处于UIViewController堆栈顶部的UIViewController的navigationItem这个属性来管理的。
UINavigationBar的外观管理
- 1.设置style
//设置bar的style
self.navigationController.navigationBar.barStyle = UIBarStyleDefault;//这种设置是白底黑字
self.navigationController.navigationBar.barStyle = UIBarStyleBlack; //这种设置是黑底白字
- 设置是否隐藏
self.navigationController.navigationBar.hidden = YES;
- 设置是否隐藏
- 3.设置背景颜色
self.navigationController.navigationBar.barTintColor = [UIColor redColor];
- 设置字体颜色
self.navigationController.navigationBar.tintColor = [UIColor blackColor];
- 设置字体颜色
- 设置标题字体属性
self.navigationController.navigationBar.titleTextAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:30], NSForegroundColorAttributeName: [UIColor whiteColor]};
UINavigationBar的内容设置
- 前面说过UINavigationBar的内容是由处于UIViewController堆栈栈顶的UIViewController的navigationItem属性来配置的。
- UINavigationBar和navigationItem有什么联系?
UINavigationItem堆栈UINavigationBar是UINavigationController的属性,我们在设置了UINavigationBar的外观后,其将作用于全部的UIViewController。navigationItem是UIViewController的属性,它是配置这个UIViewController上面的UINavigationBar的内容的。UINavigationBar中有一个堆栈,这个堆栈是一个UINavigationItem堆栈,当把一个UIViewController push进栈的时候,它的navigationItem也会被push进UINavigationBar的堆栈。所以UINavigationBar的这个堆栈和这个UIViewController堆栈是一一对应的。
我们看到UINavigationBar有一个Items属性,这个items属性就是以堆栈的形式存放每个UIViewController的navigationItem。其中栈顶的navigationItem称为topItem,栈顶下面的item称为backItem。
- UINavigationBar通过UINavigationItem堆栈按照如下方式来决定展示在UINavigationBar中的内容:
位于中间的标题会按照下面的顺序展示内容:
如果topitem设置了标题视图(titleview属性),则展示标题视图。
如果topitem设置了标题文字(title属性),则显示标题文字。
如果,什么也没有设置,则显示空白。
位于右边的按钮按照下面的顺序展示内容:
如果topitem设置了右侧按钮(rightBarButtonItem属性),则显示右侧按钮。
如果没有设置右侧按钮,则显示空白。
位于左侧的按钮会按照下列顺序显示内容:
如果topitem设置了左侧按钮(leftBarButtonItem属性),则显示左侧按钮。
如果backitem设置了返回按钮(backButtonItem属性),则显示返回按钮。
如果backitem设置了标题文字(title属性),则显示利用标题文字封装的返回按钮。
如果以上都未设置,则展示利用“Back”封装的返回按钮。
tips
在默认情况下返回按钮和左侧按钮是不同时显示的,默认是不显示左侧按钮,要使两者同时显示,可以设置:
UINavigationBar通过UINavigationItem堆栈按照如下方式来决定展示在UINavigationBar中的内容
tips
修改返回按钮的标题
//在这个页面设置,下个页面生效。
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"go" style:UIBarButtonItemStylePlain target:nil action:nil];
设置返回按钮的图片:
self.navigationController.navigationBar.backIndicatorImage = [UIImage imageNamed:@""];
self.navigationController.navigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@""];
这两句话必须同时设置才会生效。
通过手势隐藏UINavigationBar与UIToolbar
获取手势识别器
// 侧滑返回手势识别器
@property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer;
// 用于轻拍隐藏UINavigationBar与UIToolbar的手势识别器
@property(nonatomic, readonly, assign) UITapGestureRecognizer *barHideOnTapGestureRecognizer;
// 用于轻扫隐藏UINavigationBar与UIToolbar的手势识别器
@property(nonatomic, readonly, strong) UIPanGestureRecognizer *barHideOnSwipeGestureRecognizer;
// 示例
UIGestureRecognizer *interactivePopGestureRecognizer = navigationController.interactivePopGestureRecognizer;
隐藏UINavigationBar
//这样设置是对堆栈中的所有viewcontroller生效
//轻拍隐藏,再次轻拍显示
self.navigationController.hidesBarsOnTap = YES;
//向上轻扫隐藏,向下轻扫显示
self.navigationController.hidesBarsOnSwipe = YES;
//横屏隐藏(此时轻拍显示),竖屏显示.
self.navigationController.hidesBarsWhenVerticallyCompact = YES;
//键盘出现隐藏,键盘消失仍隐藏,但是轻点出现。
self.navigationController.hidesBarsWhenKeyboardAppears = YES;
网友评论