引
如我在传送门:iOS导航栏切换界面时隐藏和显示中所说,现在很多App的个人中心模块都是不保留导航栏的,会直接使导航栏透明,比如做的很好的QQ个人信息界面:
为什么说QQ做的很好呢?既然有透明的导航栏也有不透明的导航栏,那一定会在界面切换之间存在一个过渡的过程,而这个过程,QQ做的特别好,在从透明导航栏界面返回到不透明导航栏界面时,导航栏的透明度是一个渐进的过渡效果,甚至会有一种毛玻璃的效果,感兴趣的可以打开手机QQ到个人界面看一看,效果很赞。
而很多App的做法其实比较粗糙,类似于我在传送门:iOS导航栏切换界面时隐藏和显示中的做法,需要导航栏透明时,直接将导航栏隐藏起来。直接隐藏起来的意思是,整个导航栏就用不了了,也就是说,标题、返回按钮等都需要自己去做,这是一个比较麻烦的地方,此外,在有无导航栏的界面间切换时,过程是比较生硬的,导航栏不是渐变出现的。如果说这些都可以接受,那最大的一个问题,也是我在那篇文章里提到的,如果正好处于用UITabbarConatroller切换界面,那么导航栏会有一个往上缩回的快速动画,这其实就很不美观了,当然我们可以通过将隐藏导航栏的动画去掉来达到对Tabbar切换友好的效果:
[self.navigationController setNavigationBarHidden:NO animated:NO];
但是这样一来你在UINavigationController体系下切换界面时由于没有了动画,这边的效果又会变得很差。这两个矛盾没有想到可以调和的手段,除非在业务上就不显示Tabbar了,但始终不是长久之计。
同时,我们虽然说QQ做的很好,但也依然有一些不足,多把玩一下导航栏过渡的过程就会发现,如果准备从透明导航栏返回时又决定不反回了,还是停留在导航栏透明的界面,这时候导航栏虽然会回到透明,但会有一个导航栏闪现一下的小瑕疵。
现在问题已经讲完了,基于这些问题,我们自己来尝试实现一种更好的平滑过渡效果,不自定义导航栏,直接利用系统原生的导航栏,使用Category和Runtime的技术,达到这个效果:
代码可以在示例工程下载(觉得有帮助的小伙伴请不吝加Star~):https://github.com/Cloudox/SmoothNavDemo
实现过程
其实我们的目的总结起来有三个:
1、不去自定义导航栏,就用系统原生的,标题、返回按钮啥的都方便加,这也就是说不隐藏导航栏,而是要单独让导航栏背景透明;
2、在导航栏透明与否的界面间切换时透明度有渐变效果;
3、在UINavigationController体系和UITabarController体系下切换界面都很完美。
对于第三个目的,我们之前在UITabarController下切换时会有导航栏隐藏的小动画,但如果我们满足了第一个目的,那就不存在隐藏导航栏了,所以第三个问题也就不会存在了。
我们先来看第一个目的。
设置导航栏背景透明度
导航栏上应该是有很多view的,我们要做的是只让背景透明,而保留标题、返回按钮。iOS没有直接给我们提供对于导航栏背景view的访问途径,那么我们只能自己来找了。
首先我们遍历打印出UINavigationBar的所有子视图,是所有,包括子视图的一层层子视图,来看看到底导航栏都包含了哪些东西:
上面这张图就是导航栏UINavigationBar所包含的所有子view了,序号和缩进表示了其层级归属关系,打印的方法可以看这篇文章:传送门:iOS遍历打印所有子视图
从这些子view的类名能够大概猜出他们都是导航栏上的什么,让我们大胆猜测一下,_UIBarBackground 是背景视图,下属的 UIImageView 是背景图片,_UINavigationBarBackIndicatorView 是返回箭头,UINavigationItemView 是添加的一些导航栏按钮,包括返回按钮,因为我没有给导航栏添加任何其他按钮,所以这里一定是返回按钮,下属的 UILabel 就是 “返回” 两个字了。
根据上面得到的信息,我们就尝试将_UIBarBackground、UIImageView、UIVisualEffectView的 alpha 值设为 1 或者 0 来改变导航栏背景的透明度。
我们可以给 UINavigationController 创建一个类别,来给这个类添加一个方法,用于设置导航栏的透明度:
// UIViewController+Cloudox.m
- (void)setNeedsNavigationBackground:(CGFloat)alpha {
// 导航栏背景透明度设置
UIView *barBackgroundView = [[self.navigationBar subviews] objectAtIndex:0];// _UIBarBackground
UIImageView *backg