NavigationController已经洗干净了,就等你来

2016.12.04数组

很久没有更新博客了,近日把项目中遇到的NavigationController 相关技术点梳理一下,与你们共同分享app

首先来点基础的属性

一. 基本属性

  • 设置颜色 若是项目中 Navigation 都是统一的,而你又懒得单独抽取一个BaseNavigationController,能够直接在 [appDelegate didFinishLaunchingWithOptions]方法中写
//设置NavigationBar背景颜色
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];

// 经过富文本设置title 样式(这里也能够经过自定义Label,而后设置 titleView 来实现)
[[UINavigationBar appearance] setTitleTextAttributes:@{
                    NSForegroundColorAttributeName : [UIColor whiteColor]
                                                           }];

// 设置状态栏格式,若是 NavigationBar 为深色调,就设置为 UIBarStyleBlack,则状态栏显示为白色
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
复制代码
  • 实现 NavigationBar 透明效果 实现透明可能你们第一个想到的是 设置 alpha 值,可是因为设置了做为父控件的 NavigationBar 的透明度后,其子控件 BarButtonItem 也会随之改变,所以想要实现导航栏透明,可是 BarButtonItem 正常显示(相似 手机QQ 的好友动态页),能够采用下面的方法
// 设置一个空的图片背景图片,就能实现导航栏透明可是 BarButtonItem 正常显示
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
                                                forBarMetrics:UIBarMetricsDefault];
复制代码

然而设置以后乍一看没问题,可仔细一看你会发现NavigationBar下面还有一条细线,这个细线就是shadow 布局

快看那条淡淡的细线!
层级关系图

可经过如下代码来去掉动画

// 设置一个空的 shadowImage 来实现
self.navigationController.navigationBar.shadowImage = [UIImage new];
复制代码

那么有同窗可能要问了,一直透明的能够经过上述方法来实现,那若是想要随着 上拉距离的改变,实现其透明度动态变化要怎么作?ui

// 这个就要监听 scrollView 的 offset
// 而后获取到 NavigationBar复合视图 的显示子控件,动态改变其透明度
[[self.navigationController.navigationBar subviews] objectAtIndex:0].alpha = 0;
复制代码

既然讲到这里了就说下来回 push 或 pop,以及使用手势来返回的时候,上下层级之间 NavigationBar 隐藏与否的设置,由于若是这里没处理好的话,会有一个黑条,或者直接显示下一层级的视图,体验特别差,这时候就须要经过动画的方式的在下一层级进行设置spa

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    // 当前 VC 须要显示 navigationBar 就设置为 NO,须要隐藏就设置为 YES
    [self.navigationController setNavigationBarHidden:YES animated:YES];
}
复制代码
  • 侧滑手势相关 不少时候,leftBarButtonItem须要自定义,由于默认的显示上一层级的title不必定是咱们想要的,可是自定义改变以后,会发现侧滑返回的手势很差使了
#warning 这时候就须要在当前 VC 中设置手势代理了
self.interactivePopGestureRecognizer.delegate = self;

// 实现代理方法:返回 YES,则手势有效
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    //当导航控制器的子控制器个数 大于1 手势才有效
    return self.childViewControllers.count > 1;
}
复制代码
  • 因为项目中同一个 VC,有时候是 modal 出来的,有时候是 push 出来的,那么在这个VC中就要判断进行处理
NSArray *viewcontrollers=self.navigationController.viewControllers;
if (viewcontrollers.count > 1) {
    if ([viewcontrollers objectAtIndex:viewcontrollers.count - 1] == self) {
        // push方式
        [self.navigationController popViewControllerAnimated:YES];
    }
} else {    
    // present方式    
    [self dismissViewControllerAnimated:YES completion:nil];
}
复制代码
  • 若是要实现以下效果的导航栏,设置 leftBarButtonItems 和 rightBarButtonItems 便可 3d

    喂!焦点在 NavigationBar,老看 tableView 干啥!

  • 关于 rootVC 的 offset,先来看几个 ViewController 的属性 代理

  • iOS7之后默认设置是 UIRectEdgeAll,translucent 的默认值是 true,这个组合会使 rootView 的布局从 (0, 0) 开始,就会形成 rootView 被 NavigationBar 遮挡住一部分,将 edgesForExtendedLayout 设置为 UIRectEdgeNone 便可解决问题code

  • automaticallyAdjustsScrollViewInsets 默认值是 YES,表示在全屏下会自动将 第一个添加到 rootVC 的 ScrollView 的 contentInset 设置为 (64, 0, 0, 0),这样 scrollView 就不会被导航栏遮挡住了cdn

二. 来回跳转

项目中有个需求是A push 到 B, B push 到 C, C pop 到 D,D 再 pop到 A,就比如这样:

相似这种交叉跳转的感受

  • 首先 A push 到 B,直接使用
[self.navigationController pushViewController:B animated:YES];
// 此时 self.navigationController.childViewControllers = [A, B];
复制代码
  • 而后 B push 到 C,同理
[self.navigationController pushViewController:C animated:YES];
// 此时 self.navigationController.childViewControllers = [A, B, C];
复制代码
  • 如今要实现 C pop 到 D,因为 navigationController.childViewControllers 是只读的,所以不能直接对其进行操做
    navigationController.childViewControllers 是只读的
// 创建可变拷贝对象,而后进行替换操做
NSMutableArray *navChildMArr = [self.navigationController.childViewControllers mutableCopy];
[navChildMArr replaceObjectAtIndex:1 withObject:D];

// 固然,最后再将替换后的数组赋值回去不要忘了
[self.navigationController setViewControllers:navChildMArr animated:YES];

#warning 至于写上面这串代码的时机:写在 B push C 以后能够,写在 C 的 viewDidLoad() 方法中也能够
复制代码

最后的效果如图

对,效果如图

就四这么简单!

若是有其余问题,能够在留言处写下来,不按期更新

相关文章
相关标签/搜索