iOS FunUIKitios学习资料

鬼魅的“64边距”——translucent属性

2016-09-27  本文已影响1256人  聪明的笨白

总所周知,苹果从iOS7开始采用扁平化的界面风格,颠覆了果粉们“迷恋”的拟物化风格。对于开发者而言,全新的风格带来新的接口,这些新的接口改动中,有些更加合理了,有些更加方便了,而有些可能让开发者容易迷糊,下面本人就来谈谈iOS7这些新添加“鬼魅”的接口中的经常接触到的一个----UITabBar/UINavigationBar的translucent属性。

新的属性translucent简介

顾名思义,translucent属性能决定UITabBar/UINavigationBar是否为半透明的效果,苹果官方对此的解释如下:

/*
 New behavior on iOS 7.
 Default is YES.
 You may force an opaque background by setting the property to NO.
 If the navigation bar has a custom background image, the default is inferred 
 from the alpha values of the image—YES if it has any pixel with alpha < 1.0
 If you send setTranslucent:YES to a bar with an opaque custom background image
 it will apply a system opacity less than 1.0 to the image.
 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.
 */
@property(nonatomic,assign,getter=isTranslucent) BOOL translucent NS_AVAILABLE_IOS(3_0) UI_APPEARANCE_SELECTOR; 
// Default is NO on iOS 6 and earlier. Always YES if barStyle is set to UIBarStyleBlackTranslucent
/*
 Default is YES.
 You may force an opaque background by setting the property to NO.
 If the tab bar has a custom background image, the default is inferred from the alpha
 values of the image—YES if it has any pixel with alpha < 1.0
 If you send setTranslucent:YES to a tab bar with an opaque custom background image
 the tab bar will apply a system opacity less than 1.0 to the image.
 If you send setTranslucent:NO to a tab bar with a translucent custom background image
 the tab bar 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.
 */
@property(nonatomic,getter=isTranslucent) BOOL translucent NS_AVAILABLE_IOS(7_0);

简而言之,这个BOOL属性能控制UITabBar/UINavigationBar的半透明效果,默认为YES,即默认情况下为半透明效果(后面会详细解释这两段官方文字描述的含义)。

translucent缘何“鬼魅”

新属性的出现往往会导致一些“注意事项”,主要体现为被半透明效果处理后产生的色差和添加的类view控件的坐标变动。

默认情况下,如果使用UITabBarController和UINavigationBarController(translucent属性默认为YES),设置一个蓝色的view添加其中并设置距离屏幕边距为(0,0,0,0),展示效果如下:


view默认情况示例.png

可以看到,UITabBarController和UINavigationBarController被蓝色的view“穿透”了,此时view的边距也正如设置的一样,零点坐标在(0,0)处。

这时候,如果将view替换成tableView,展示效果如下:


tableView默认情况示例1.png
tableView默认情况示例2.png

可以看到,tableView的cell并没有因为“穿透”效果而出现被遮挡的情况,这是由于苹果对滚动视图的特殊性进行处理:对于类ScrollView,系统默认默认控制器属性automaticallyAdjustsScrollViewInsets默认为YES。

请注意:iOS11开始,苹果摒弃了automaticallyAdjustsScrollViewInsets属性,改由contentInsetAdjustmentBehavior(枚举值)控制,下面会有详细的解释。

// 宏定义解析:看UIScrollView实例是否响应setContentInsetAdjustmentBehavior方法,响应则赋值2(2表示枚举值UIScrollViewContentInsetAdjustmentNever),否则设置视图控制器的automaticallyAdjustsScrollViewInsets = NO,_Pragma包括的代码表示消除-Warc-performSelector-leaks警告。
#define  adjustsScrollViewInsets_NO(scrollView,vc)\
do { \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
        if ([UIScrollView instancesRespondToSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:")]) {\
            [scrollView   performSelector:NSSelectorFromString(@"setContentInsetAdjustmentBehavior:") withObject:@(2)];\
        } else {\
            vc.automaticallyAdjustsScrollViewInsets = NO;\
        }\
    _Pragma("clang diagnostic pop") \
} while (0)

首先来看下在Xcode 9的SDK中关于原有属性automaticallyAdjustsScrollViewInsets的描述:

@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets API_DEPRECATED_WITH_REPLACEMENT("Use UIScrollView's contentInsetAdjustmentBehavior instead", ios(7.0,11.0),tvos(7.0,11.0)); // Defaults to YES
// 中文解析:此API已经过期且被UIScrollView下的contentInsetAdjustmentBehavior属性替代

这里描述得很清楚了,iOS11之后该属性过期了!那么接下来我们看看替代属性到底是啥:

/* Configure the behavior of adjustedContentInset.
 Default is UIScrollViewContentInsetAdjustmentAutomatic.
 中文解析:该属性用来配置UIScrollView调整内边距的行为,其值为枚举值,默认值是UIScrollViewContentInsetAdjustmentAutomatic,就是自动调整。
 */
@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior API_AVAILABLE(ios(11.0),tvos(11.0));

// 以下是该枚举的具体值(选项)
typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {
    // 中文解析:与UIScrollViewContentInsetAdjustmentScrollableAxes相似,但为了向后兼容(向低版本兼容),当scroll view被view controller管理,且该view controller的automaticallyAdjustsScrollViewInsets = YES并在导航条控制器栈内,该枚举也会调整顶部(导航条)和底部(Tabbar)的内边距,无论该scroll view是否可滚动。
    UIScrollViewContentInsetAdjustmentAutomatic, // Similar to .scrollableAxes, but for backward compatibility will also adjust the top & bottom contentInset when the scroll view is owned by a view controller with automaticallyAdjustsScrollViewInsets = YES inside a navigation controller, regardless of whether the scroll view is scrollable

    // 中文解析:滚动轴的边缘会被调整(例如contentSize.width/height > frame.size.width/height 或 alwaysBounceHorizontal/Vertical = YES)
    UIScrollViewContentInsetAdjustmentScrollableAxes, // Edges for scrollable axes are adjusted (i.e., contentSize.width/height > frame.size.width/height or alwaysBounceHorizontal/Vertical = YES)

    // 中文解析:内边距不会被调整
    UIScrollViewContentInsetAdjustmentNever, // contentInset is not adjusted

    // 中文解析:内边距总是被scroll view的safeAreaInsets所调整,safeAreaInsets顾名思义就是safeArea的内边距,safeArea下面会有一个概括性的解释。
    UIScrollViewContentInsetAdjustmentAlways, // contentInset is always adjusted by the scroll view's safeAreaInsets
} API_AVAILABLE(ios(11.0),tvos(11.0));

safeArea概括性解释:表示一个区域,该区域避开了导航条、Tabbar等可能挡住view controller的view的控件,如果添加一个view控件是相对于它父控件的safeAreaLayoutGuide做布局,则不用担心被导航条、Tabbar等控件“挡住”

视图控制器view的safeArea.png

针对非滚动视图的需求

由上述内容我们知道,默认情况下,导航条和TabBar都是半透明,添加在上面的控制器的视图会有“穿透”效果。如果现在有这样的需求:对于非滚动视图,从原点(0,0)布局,但是内容不被遮挡,能够正常显示。
这时候我们需要区分两种情况:是否需要导航条/TabBar带有半透明效果。

关于iOS7之后与view全屏相关的知识点

在iOS7之后,默认情况下,控制器的view是”全屏“的,也就是说,即便有TabBar或者NavigationBar,控制器的view也是可以”穿透至全屏“的,针对这一特性,苹果对UIViewController提供了以下几个属性供开发者使用:

// 在iOS7之前,控制器的view默认非全屏,如果想要全屏效果,需要设置为YES,该属性已从iOS7开始过期
@property(nonatomic,assign) BOOL wantsFullScreenLayout NS_DEPRECATED_IOS(3_0, 7_0) __TVOS_PROHIBITED; 
// Deprecated in 7_0, Replaced by the following:  该属性被以下三个属性代替


// Defaults to UIRectEdgeAll
@property(nonatomic,assign) UIRectEdge edgesForExtendedLayout NS_AVAILABLE_IOS(7_0); 

// Defaults to NO, but bars are translucent by default on 7_0.  
@property(nonatomic,assign) BOOL extendedLayoutIncludesOpaqueBars NS_AVAILABLE_IOS(7_0); 

// Defaults to YES
@property(nonatomic,assign) BOOL automaticallyAdjustsScrollViewInsets NS_AVAILABLE_IOS(7_0); 

下面解释一下这三个属性:

设置导航条或者TabBar背景图片的注意事项

这里会详细解释官方文档对translucent属性的注释,为什么放到这里才说?因为官方文档对该属性的解释全部跟设置导航条或者TabBar的背景图片有关!说明苹果也知道,这里坑很多,下面就来梳理一下吧。。。

translucent属性的官方解释
设置导航栏背景图片透明度问题
上一篇 下一篇

猜你喜欢

热点阅读