UINavigationBar
这玩意本身就有点复杂,然后iOS11的一些新特性让这玩意又重新进入了视野,并且要对之前所做的效果做新的适配。
Translucent
navigationBar的这个属性是整个导航栏的核心属性,默认为YES。小小一个属性所影响的效果可不紧紧是它的字面意思——是否半透明,这么简单。
毛玻璃效果
当你不做任何设置,由于bar的Translucent为YES,self.view的起始坐标是从设备真正的左上角开始的。此时(高能预警),当你是以代码的方式把tb以self.view.bounds add到 self.view时,tb的内容会被遮挡掉64像素;而当是由sb/xib创建的vc初始化来的,则会由于vc的automaticallyAdjustsScrollViewInsets(iOS11中被废弃,而成为了scrollview的属性,叫做contentInsetAdjustmentBehavior)的属性,自动把contentview的insert下移64像素防止内容被遮挡,但是因为大多数情况下我们会把下拉刷新的图标动画放在tb的正常content之外,所以由于毛玻璃效果我们可以隐约看到下拉刷新图标,不太友好;而如果把tb手动设置frame下移64像素,那完全失去了毛玻璃效果带来的视觉感受,最重要的是,你通过设置barTintColor改变导航栏颜色,会由于毛玻璃效果的存在而跟设计稿有微微的不符。于是,默认Translucent为YES时的毛玻璃这个效果对于大多数实际情况来说实在太过于鸡肋而不被使用。结构如下图:
不做任何设置的UINavigationBar注:此时的UIBarBackgound视图是透明的,毛玻璃的效果是通过UIVisualEffectView实现的。其内部的UIImageView是底部的细线,可通过subviews+下标找寻并做隐藏或替换等操作。
那么怎么取消毛玻璃效果呢?最简单的方式是:Translucent属性赋值为NO。但这样设置,navigationBar的层级中,名为UIBarBackgound的View的背景色将被设置为不透明,最重要的是,这个属性将在视图push/pop时发生作用,使传统设置透明度的方法(根据bar的subview的方法找到UIBarBackgound然后强制设置aphla)有bug:在push/pop动画进行中和结束后,系统会自动初始化UIBarBackgound,包括透明度、是否隐藏等属性,导致写在viewWillAppear和viewDidLoad中的设置透明度等属性的方法失效,而在viewDidAppear中又会出现闪烁的情况,而且侧滑手势更是会在viewDidAppear执行之后,又再次初始化UIBarBackgound。但这个bug在iOS11之前好像是不存在的+。设置成NO时的层级如下图:
Translucent为NO,背景色不透明透明度设置
首先,无论何时,设置导航栏的透明度都不能通过含透明度的颜色来设置,因为barTintColor的通道是不能识别透明度的(比如设置clearcolor,你将会看到纯黑色的效果)。且如果设置了barTintColor,则无法通过设置UIBarBackgound的透明度来实现设置导航栏的透明度了。
所以最终选择的方案是在navigationBar.subviews添加一个全局背景视图,既可以用自定义的颜色、透明度,甚至可以放图片。(或者vc的view中单独添加)
PS:后来发现无论何时移除UIBarBackgound这个view都无济于事,因为转场动画一定会初始化导航栏,所以Translucent设为NO,导航栏的透明度将变得几乎无法控制。上述方法只适用于Translucent为YES的情况。