注意:
要回到指定的控制器,这个指定的控制器必须得是导航控制器的子控制器。
当一个控制器被pop后,控制器内存就被释放了(会调用deinit/dealloc函数。
控制器被销毁,它的view不一定就销毁(只要有storng指针),但是当一个控制器被销毁,那么它的view的业务逻辑无法处理。
设置导航条的内容
由栈顶控制器的navigationItem属性来决定导航条的内容,在栈顶控制器的.m的viewDidLoad{ }中设置
其中,titleView可以设为各种控件
设置navBar的字体大小,颜色
- [nav.navigationBar setTitleTextAttributes:@{
- NSFontAttributeName:[UIFont systemFontOfSize:19],
- NSForegroundColorAttributeName:[UIColor whiteColor]
- }];
- navBar的隐藏状态:navController.navigationBarHidden = YES;
UINavigationBar通过UINavigationItem堆栈,按照如下方式来决定展示在UINavigationBar中的内容
- 位于中间的标题会根据下方顺序选择展示的内容:
如果topItem设置了标题视图(titleView属性), 则展示标题视图
如果topItem设置了标题文字(title属性), 则展示标题文字
如果以上都未设置, 则展示空白。
- 位于右侧的按钮会根据下方顺序选择展示的内容:
如topItem设置了右侧按钮(rightBarButtonItem属性)则展示右侧按钮
如果以上都未设置, 则展示空白。
- 位于左侧的按钮会根据下方顺序选择展示的内容:
如topItem设置了左侧按钮(leftBarButtonItem属性), 则展示左侧按钮
如backItem设置了返回按钮(backBarButtonItem), 则展示返回按钮
如backItem设置了标题(title), 则展示用标题文字封装的返回按钮
- 如果以上都未设置, 则展示利用文字"Back"封装的返回按钮。
设置导航条的外观
UINavigationBar类中提供了大量属性/方法用于设置其外观, 我们可以设置其样式、背景颜色、色彩颜色、文字属性,同样, 我们也可以设置其背景图片、阴影图片。
- 样式:navigationBar.barStyle
该属性可为UIBarStyleDefault(白底黑字)、UIBarStyleBlack(黑底白字)
- 背景色:navigationBar.barTintColor
- 前景色:navigationBar.tintColor
- 设置背景图片:[navigationBar setBackgroundImage:。。。];
- 阴影图片:navigationBar.shadowImage = [UIImage imageNamed:@""];
区分关系:
NavigaitonBar是导航栏,位于屏幕上方,管理整个导航控制器的navigationItem,它类似navigationcontroller一样,提供了一个栈来管理UINavigationItem。在编程时,一般只设置每个控制器的navigationItem属性。
一个导航控制器管理多个视图控制器(多个视图控制器共享一个导航控制器),而一个导航控制器只有一个UINavigationBar,被管理的多个视图控制器共享这一个UINavigationBar,只要一个视图控制器改变了UINavigationBar的属性则影响是全局的。
每个视图控制器都会有属于自己的UINavigationItem,系统会以懒加载的方式创建一个UINavigationItem显示在UINavigationBar中,改变UINavigationItem只会在当前控制器起作用,不会影响其它控制器。
通过storybord跳转控制器
设根控制器为导航控制器(删掉默认的控制器,拖入nav,设之为默认即添加箭头,添加导航控制器的根控制器(viewcontroler),方法是采用拖线的方式,点击rootcontroler;再拖入一个viewcontroler,实现控制器之间的跳转,方法是拖线(从一个按钮拖到下一个控制器,点击show选项)
设置导航条的内容(可以把其他控件如item等拖到导航条;可以设导航条标题;
自定义导航控制器
- +(void)initialize{
- // 获取APP的导航条标识
- // UINavigationBar *bar = [UINavigationBar appearance]; //这种写法有bug,它会代表app中所有的导航条,当app中还有自定义导航条时也会被包含
- UINavigationBar *bar = [UINavigationBar appearanceWhenContainedIn:[PDNavigationViewController class],nil]; //(获取指定某几个类的导航条标识)
- //设置nav bar的背景图片(因无法设置背景颜色)
- [bar setBackgroundImage:[UIImage imageNamed:@"navBar"] forBarMetrics:UIBarMetricsDefault];
- //标题字体大小、颜色
- NSMutableDictionary *dict = [NSMutableDictionary dictionary];
- dict[NSFontAttributeName] = [UIFont systemFontOfSize:22.0];
- dict[NSForegroundColorAttributeName] = [UIColor whiteColor];
- [bar setTitleTextAttributes:dict];
- }
统一样式只需设一次即可。因此,在initialize方法中设置,此方法当当前类第一次初始化的时候才调用,这样就实现只设置一次。当然在加载时viewDidLoad方法也只调用一次,但是一个缺点就是,当要创建多个导航控制器时,会调用(设置)多次。
- -(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
- [super pushViewController:viewController animated:animated];
- //判断当前不是在根控制器下,此时设置leftBarButtonItem
- if(self.viewControllers.count > 1)
- viewController.navigationItem.leftBarButtonItem =
- [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"nearby"]
- style:0 target:self action:@selector(back)];
- }
- -(void)back{
- [self popViewControllerAnimated:YES]; //pop返回上层
- }
(此时就系统没有了滑动返回功能)
- 恢复滑动返回功能
原理:通过清空代理的方式可以恢复
self.interactivePopGestureRecognizer.delegate = nil;
但是存在bug,因为清空之后会带来后续影响,改善如下:
- @interface PDNavigationViewController ()<UINavigationControllerDelegate>
- @property(nonatomic,strong) id popGesture; //用于暂存
- @end
- -(void)viewDidLoad {
- [super viewDidLoad];
- self.popGesture = self.interactivePopGestureRecognizer.delegate; //暂存代理
- self.delegate = self; //将代理设为自身
- }
在导航控制器代理方法中清空代理,此方法当控制器显示完毕时调用,因此能够拿到当前的控制器
- -(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
- //根控制器中不需滑动返回,此时还原代理
- if(self.viewControllers[0] == viewController){ //当前是根控制器时
- self.interactivePopGestureRecognizer.delegate = self.popGesture; //还原代理
- }else{ //非根控制器时,清空代理( 恢复滑动返回功能 )
- self.interactivePopGestureRecognizer.delegate = nil;
- }
- }
- 实现全屏滑动返回( 系统默认从左侧滑动才能返回 )
- -(void)viewDidLoad {
- [super viewDidLoad];
- //以下代码实现全屏滑动返回
- id target = self.interactivePopGestureRecognizer.delegate;
- self.interactivePopGestureRecognizer.enabled = NO;
-
- UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
- [self.view addGestureRecognizer:pan];
-
- pan.delegate = self;
- }
解决全屏滑动的bug
- //当开始滑动就会调用
- -(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
- //如果是在非根控制器,才允许滑动
- BOOL open = self.viewControllers.count > 1;
- return open;
- }