UINavigationBar的translucent、barTintColor、backgroundImage

| 导语 为了方便探讨,我把通过setBackgroundImage: forBarPosition: barMetrics:方法设置的image称为backgroundImage

translucent、barTintColor、backgroundImage三者共同决定了UINavigationBar的背景效果,而translucent在中间起非常关键的作用,它决定了系统如何使用barTintColor和backgroundImage去设置UINavigationBar的背景效果。

一、translucent设置为NO

如果设置为NO,注意是“设置为NO”,也就是主动调用setter方法,这和“值为NO”有区别,区别在什么地方后面再讲。主动设置为NO,系统会怎样使用barTintColor和backgroundImage去设置UINavigationBar的背景效果呢?先看一下系统注释:

If you send setTranslucent:NO to a bar with a translucent custom background image 
it will provide an opaque background for the image using the bar's barTintColor if defined,
or black for UIBarStyleBlack or white for UIBarStyleDefault if barTintColor is nil.

主要意思是,如果设置为NO,backgroundImage若是半透明的图,则会使用barTintColor为backgroundImage创建一个不透明的背景,事实是不是这样呢?通过代码来验证,结论是:

1. 无论backgroundImage是nil、半透明的图,还是不透明的图,系统都会使用barTintColor来设置一个不透明的背景。且barTintColor的alpha值不起作用,一直为1。

2. 不透明的背景类型是_UIBarBackground,一个私有类,继承自UIView,它的背景色被设置成了barTintColor。承载backgroundImage的UIImageView是_UIBarBackground的子视图。(这里暂且不分类和实例)

3. 如果backgroundImage是半透明,则UINavigationBar的实际背景效果就是backgroundImage和barTintColor叠加的效果,如果是不透明,则UINavigationBar的实际背景效果就是backgroundImage。

UINavigationBar的translucent、barTintColor、backgroundImage

UINavigationBar的translucent、barTintColor、backgroundImage

UINavigationBar的translucent、barTintColor、backgroundImage

如图,barTintColor是红色,backgroundImage是一张半透明图,UINavigationBar的实际背景效果就是两个图叠加而成的效果:

UINavigationBar的translucent、barTintColor、backgroundImage

 

二、translucent设置为YES

和设置为NO一样,“设置为YES”和“值为YES”有区别,如果主动调用setter方法,设置为YES,UINavigationBar的背景行为特性又会怎样呢?通过代码验证,结论是:

1. 如果设置了半透明的backgroundImage,那么UINavigationBar背景实际效果就是backgroundImage的效果,如果是完全透明的图片,那UINavigationBar背景实际效果就是完全透明。

2. 如果设置了不透明的backgroundImage,那系统会强制将backgroundImage改为半透明,UINavigationBar背景实际效果就是backgroundImage半透明的效果;这个强制修改的alpha是多少呢?看打印结果可以知道答案。alpha = 0.909804

<UIImageView: 0x123e4dae0; frame = (0 0; 375 64); alpha = 0.909804; opaque = NO; 
userInteractionEnabled = NO; layer = <CALayer: 0x2810aba00>>

3.如果设置了backgroundImage,那barTintColor将不起任何效果。

4. 如果没有设置backgroundImage,那系统会使用barTintColor来设置UINavigationBar背景效果,而且带有一点模糊效果,无论barTintColor的alpha值是多少,都不起作用,会被强制修改为一个值,具体值是多少呢?看打印可以知道答案。alpha=0.85

<_UIVisualEffectSubview: 0x115d240f0; frame = (0 0; 375 64); alpha = 0.85; autoresize = W+H; 
userInteractionEnabled = NO; layer = <CALayer: 0x280a9a180>>

三、不主动设置translucent

translucent系统默认值为YES,如果既不设置为NO,也不设置为YES,即不主动调用setter方法,UINavigationBar的背景行为特性又会怎样呢?通过代码验证,结论是:

不主动设置translucent和主动把translucent设置为YES基本一样,不一样的地方是第二点.

2. 如果设置了不透明的backgroundImage,那系统会不会强制将backgroundImage改为半透明,UINavigationBar背景实际效果就是不透明的backgroundImage。此时打印translucent的值,会发现变成了NO。如果设置了透明的backgroundImage,打印translucent的值,会发现又变成了YES。挺有意思吧

四、translucent的值

现在能理解为什么前面说“设置为NO”和“值为NO”有区别了吧。通过以上代码验证,得出结论:

1. 如果主动设置translucent,那translucent就会一直是设置的那个值,除非再次主动设置新值。

2. 如果不主动设置translucent,那translucent的值由backgroundImage决定,backgroundImage透明则为YES,backgroundImage不透明则为NO,如果没有backgroundImage,则一直是默认的YES。

五、设置导航栏背景的最佳实践

通过以上分析,我们知道不主动设置translucent可以得到有更多的*性,不管设置透明的还是不透明背景都可以通过设置backgroundImage实现。所以设置导航栏背景的最佳实践是不主动设置translucent,通过setBackgroundImage: forBarPosition: barMetrics:或setBackgroundImage: forBarMetrics:方法设置背景。大部分情况我们的导航栏是纯色背景,则通过颜色创建一张图片去设置backgroundImage。在我们项目中,为了方便通过颜色设置背景图,为UINavigationBar添加了一个方法:

@interface UINavigationBar (IGAppearance)
- (void)ig_setBackgroundImageByColor:(UIColor *)imageColor forBarMetrics:(UIBarMetrics)barMetrics;
@end

六、在什么时机设置导航栏背景色呢?如果同一个导航上的两个页面导航栏背景不一样,该如何设置?

且听下回分解。

最后感谢大家的阅读,欢迎大家提出问题和建议。