NavigationController 已经洗干净了, 就等你来
<p>好久没有更新了,近日把项目中遇到的NavigationController 相关技术点梳理一下,与大家共同分享</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/08682a2fa584011c89ebc2d698c5f71f.png"></p> <p>首先来点基础的属性</p> <h3>一. 基本属性</h3> <ul> <li> <p>设置颜色</p> <p>如果项目中 Navigation 都是统一的,而你又懒得单独抽取一个BaseNavigationController,可以直接在 [appDelegate didFinishLaunchingWithOptions]方法中写</p> </li> </ul> <pre> <code class="language-objectivec">//设置NavigationBar背景颜色 [[UINavigationBar appearance] setBarTintColor:[UIColor redColor]]; // 通过富文本设置title 样式(这里也可以通过自定义Label,然后设置 titleView 来实现) [[UINavigationBar appearance] setTitleTextAttributes:@{ NSForegroundColorAttributeName : [UIColor whiteColor] }]; // 设置状态栏格式,如果 NavigationBar 为深色调,就设置为 UIBarStyleBlack,则状态栏显示为白色 [[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];</code></pre> <ul> <li style="text-align:center"> <p>实现 NavigationBar 透明效果</p> <p>实现透明可能大家第一个想到的是 设置 alpha 值,但是由于设置了作为父控件的 NavigationBar 的透明度后,其子控件 BarButtonItem 也会随之改变,因此想要实现导航栏透明,但是 BarButtonItem 正常显示(类似 手机QQ 的好友动态页),可以采用下面的方法</p> <pre> <code class="language-objectivec">// 设置一个空的图片背景图片,就能实现导航栏透明但是 BarButtonItem 正常显示 [self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];</code></pre> <p>然而设置之后乍一看没问题,可仔细一看你会发现NavigationBar下面还有一条细线,这个细线就是shadow</p> <img src="https://simg.open-open.com/show/eb8c8d927da1abdf1ce4c0090e58e8c1.png"> <p>快看那条淡淡的细线!</p> <img src="https://simg.open-open.com/show/73955e74a50709b1719a93e7c33c0fdb.png"> <p>层级关系图</p> </li> </ul> <p>可通过以下代码来去掉</p> <pre> <code class="language-objectivec">// 设置一个空的 shadowImage 来实现 self.navigationController.navigationBar.shadowImage = [UIImage new];</code></pre> <p>那么有同学可能要问了,一直透明的可以通过上述方法来实现,那如果想要随着 上拉距离的改变,实现其透明度动态变化要怎么做?</p> <pre> <code class="language-objectivec">// 这个就要监听 scrollView 的 offset // 然后获取到 NavigationBar复合视图 的显示子控件,动态改变其透明度 [[self.navigationController.navigationBar subviews] objectAtIndex:0].alpha = 0;</code></pre> <p>既然讲到这里了就说下来回 push 或 pop,以及使用手势来返回的时候,上下层级之间 NavigationBar 隐藏与否的设置,因为如果这里没处理好的话,会有一个黑条,或者直接显示下一层级的视图,体验特别差,这时候就需要通过动画的方式的在下一层级进行设置</p> <pre> <code class="language-objectivec">- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; // 当前 VC 需要显示 navigationBar 就设置为 NO,需要隐藏就设置为 YES [self.navigationController setNavigationBarHidden:YES animated:YES]; }</code></pre> <ul> <li> <p>侧滑手势相关</p> <p>很多时候,leftBarButtonItem需要自定义,因为默认的显示上一层级的title不一定是我们想要的,但是自定义改变之后,会发现侧滑返回的手势不好使了</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/f1e28de6020849c8bff40c8d02c5d6c0.png"></p> </li> </ul> <pre> <code class="language-objectivec">#warning 这时候就需要在当前 VC 中设置手势代理了 self.interactivePopGestureRecognizer.delegate = self; // 实现代理方法:返回 YES,则手势有效 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { //当导航控制器的子控制器个数 大于1 手势才有效 return self.childViewControllers.count > 1; }</code></pre> <ul> <li> <p>由于项目中同一个 VC,有时候是 modal 出来的,有时候是 push 出来的,那么在这个VC中就要判断进行处理</p> <pre> <code class="language-objectivec">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]; }</code></pre> </li> <li style="text-align:center"> <p>如果要实现如下效果的导航栏,设置 leftBarButtonItems 和 rightBarButtonItems 即可</p> <img src="https://simg.open-open.com/show/e9717bdcb870d0f07aa20d13ececc644.png"> <p>喂!焦点在 NavigationBar,老看 tableView 干啥!</p> </li> <li> <p>关于 rootVC 的 offset,先来看几个 ViewController 的属性</p> <p><img src="https://simg.open-open.com/show/44360bcb62dce712af02c0163f47e8ad.png"></p> <ul> <li>iOS7以后默认设置是 UIRectEdgeAll,translucent 的默认值是 true,这个组合会使 rootView 的布局从 (0, 0) 开始,就会造成 rootView 被 NavigationBar 遮挡住一部分,将 edgesForExtendedLayout 设置为 UIRectEdgeNone 即可解决问题</li> <li>automaticallyAdjustsScrollViewInsets 默认值是 YES,表示在全屏下会自动将 第一个添加到 rootVC 的 ScrollView 的 contentInset 设置为 (64, 0, 0, 0),这样 scrollView 就不会被导航栏遮挡住了</li> </ul> </li> </ul> <p>二. 来回跳转</p> <p>项目中有个需求是A push 到 B, B push 到 C, C pop 到 D,D 再 pop到 A,就好比这样:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/0cdd38befb079f8612aa635b9f8f6309.gif"></p> <p style="text-align:center">类似这种交叉跳转的感觉</p> <ul> <li>首先 A push 到 B,直接使用 <pre> <code class="language-objectivec">[self.navigationController pushViewController:B animated:YES]; // 此时 self.navigationController.childViewControllers = [A, B];</code></pre> </li> <li>然后 B push 到 C,同理 <pre> <code class="language-objectivec">[self.navigationController pushViewController:C animated:YES]; // 此时 self.navigationController.childViewControllers = [A, B, C];</code></pre> </li> <li>现在要实现 C pop 到 D,由于 navigationController.childViewControllers 是只读的,因此不能直接对其进行操作<br> <img src="https://simg.open-open.com/show/6752ad3e9f11a6dc6eee09f05df4f610.png"> <p style="text-align:center">navigationController.childViewControllers 是只读的</p> </li> </ul> <pre> <code class="language-objectivec">// 建立可变拷贝对象,然后进行替换操作 NSMutableArray *navChildMArr = [self.navigationController.childViewControllers mutableCopy]; [navChildMArr replaceObjectAtIndex:1 withObject:D]; // 当然,最后再将替换后的数组赋值回去不要忘了 [self.navigationController setViewControllers:navChildMArr animated:YES]; #warning 至于写上面这串代码的时机:写在 B push C 之后可以,写在 C 的 viewDidLoad() 方法中也可以</code></pre> <p>最后的效果如图</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/ac9660799cebf576bedc76bbe496f5e4.gif"></p> <p style="text-align:center">对,效果如图</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/c26e4670ec4381d434c8261e0769071e.png"></p> <p style="text-align:center">就四这么简单!</p> <p>如果有其他问题,可以在留言处写下来,不定期更新</p> <p> </p> <p>来自:http://www.jianshu.com/p/a1a0c053fb12</p> <p> </p>
本文由用户 fwdrtywndp 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
转载本站原创文章,请注明出处,并保留原始链接、图片水印。
本站是一个以用户分享为主的开源技术平台,欢迎各类分享!