鬼魅的“64邊距”——translucent屬性

總所周知恨课,蘋果從iOS7開始采用扁平化的界面風格,顛覆了果粉們“迷戀”的擬物化風格磨德。對于開發(fā)者而言缘回,全新的風格帶來新的接口吆视,這些新的接口改動中,有些更加合理了酥宴,有些更加方便了啦吧,而有些可能讓開發(fā)者容易迷糊,下面本人就來談談iOS7這些新添加“鬼魅”的接口中的經(jīng)常接觸到的一個----UITabBar/UINavigationBar的translucent屬性拙寡。

新的屬性translucent簡介

顧名思義授滓,translucent屬性能決定UITabBar/UINavigationBar是否為半透明的效果,蘋果官方對此的解釋如下:

  • UINavigationBar的translucent屬性解釋
/*
 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
  • UITabBar的translucent屬性解釋
/*
 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緣何“鬼魅”

新屬性的出現(xiàn)往往會導致一些“注意事項”淮摔,主要體現(xiàn)為被半透明效果處理后產(chǎn)生的色差和添加的類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并沒有因為“穿透”效果而出現(xiàn)被遮擋的情況,這是由于蘋果對滾動視圖的特殊性進行處理:對于類ScrollView排龄,系統(tǒng)默認控制器屬性automaticallyAdjustsScrollViewInsets默認為YES波势。

請注意:iOS11開始,蘋果摒棄了automaticallyAdjustsScrollViewInsets屬性橄维,改由contentInsetAdjustmentBehavior(枚舉值)控制尺铣,下面會有詳細的解釋。

  • automaticallyAdjustsScrollViewInsets = YES時系統(tǒng)底層所干的事
    scrollView的內容原本沒有內邊距争舞,但是考慮到導航欄(高度44px)凛忿、狀態(tài)欄(高度20px)、TabBar(高度49px)會擋住后面scrollView所展示的內容竞川,系統(tǒng)自動為scrollView增加上下的內邊距店溢,這時候我們打印一下tableView的描述(友情提示:tableView繼承自scrollView):

    tableView描述.png

    可以看出叁熔,contentOffset(內容坐標偏移量)和contentSize(內容尺寸大小)都發(fā)生了變化逞怨,結合tableView自身的frame可以看出者疤,系統(tǒng)自動為scrollView增加了頂部64px的內邊距以及底部49px的內邊距,正好是導航欄高度+狀態(tài)欄高度以及TabBar高度叠赦。一旦手動在系統(tǒng)布局頁面之前設置automaticallyAdjustsScrollViewInsets = NO驹马,將會取消上述操作,屆時scrollView內容將會被部分擋住除秀。
    請注意:上述的情況僅僅對UIScrollView或者子類(如UITableView)有效糯累。

  • contentInsetAdjustmentBehavior定義及使用(適用于iOS11+,替代automaticallyAdjustsScrollViewInsets)
    如果只想單純地設置導航條不偏移導航條+狀態(tài)欄和Tabbar高度册踩,不想看解釋泳姐,可以直接使用該宏定義解決方法適配的問題(宏定義來源:http://www.reibang.com/p/352f101d6df1):

// 宏定義解析:看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已經(jīng)過期且被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概括性解釋:表示一個區(qū)域弟头,該區(qū)域避開了導航條、Tabbar等可能擋住view controller的view的控件涉茧,如果添加一個view控件是相對于它父控件的safeAreaLayoutGuide做布局赴恨,則不用擔心被導航條、Tabbar等控件“擋住”

視圖控制器view的safeArea.png

  • 非滾動視圖中導致“鬼魅”的原因
    從上述內容中伴栓,我們可以了解到滾動視圖默認情況下系統(tǒng)會給滾動內容增加上下內邊距伦连,以防內容被導航條和TabBar遮擋雨饺,但是實際上在常用的項目界面結構(TabBarController--NavigationController--ViewController)以及系統(tǒng)默認情況下,viewController中的view是沒有內邊距的(也就是說view穿透上下兩個Bar)惑淳。但是我們有時候會看到應用中會有這樣的情形:非滾動視圖依然有類似增加上下內邊距的效果额港,自己并沒有手動更改過視圖的frame。這種情況歧焦,就要結合其他幾個系統(tǒng)的屬性來解釋了移斩。

針對非滾動視圖的需求

由上述內容我們知道,默認情況下绢馍,導航條和TabBar都是半透明向瓷,添加在上面的控制器的視圖會有“穿透”效果。如果現(xiàn)在有這樣的需求:對于非滾動視圖舰涌,從原點(0猖任,0)布局,但是內容不被遮擋瓷耙,能夠正常顯示朱躺。
這時候我們需要區(qū)分兩種情況:是否需要導航條/TabBar帶有半透明效果。

  • 保留半透明效果(導航條/TabBar的translucent == YES)

    1. 手動修改frame布局搁痛,從(0长搀,64)開始布局,底部同理落追,需要計算坐標尺寸盈滴,比較繁瑣。
    2. 修改viewController的edgesForExtendedLayout屬性轿钠,edgesForExtendedLayout = UIRectEdgeNone
      (備注:設置后巢钓,控制器的view的frame的坐標Y增加64px緊挨著navigationBar下方,底部同理疗垛,該屬性支持iOS7及以后的版本症汹。)
      注意:這里雖然看著導航條和TabBar還有半透明效果,但是實際上下面的內容已經(jīng)無法再”穿透“了贷腕。
      運行效果如下圖所示:


      edgesForExtendedLayout = UIRectEdgeNone效果展示.png
  • 不保留半透明效果(導航條/TabBar的translucent == NO)
    將TabBar和導航條的translucent屬性分別設置為NO背镇,不做任何其他修改,此時bar的背景顏色為默認的白色泽裳,且不再有色差瞒斩,運行效果如下圖所示:


    導航條的translucent設置為NO效果展示.png

    TabBar的translucent設置為NO效果展示.png

關于iOS7之后與view全屏相關的知識點

在iOS7之后,默認情況下涮总,控制器的view是”全屏“的胸囱,也就是說,即便有TabBar或者NavigationBar瀑梗,控制器的view也是可以”穿透至全屏“的烹笔,針對這一特性裳扯,蘋果對UIViewController提供了以下幾個屬性供開發(fā)者使用:

// 在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); 

下面解釋一下這三個屬性:

  • edgesForExtendedLayout:意思是view的邊緣允許額外布局的情況允蜈,默認為UIRectEdgeAll冤吨,意味著全屏布局(帶穿透效果)。

  • extendedLayoutIncludesOpaqueBars:意思是額外布局是否包括不透明的Bar陷寝,默認為NO锅很,意味著如果導航條或者TabBar非透明,view內容不會被他們遮擋凤跑,如果該屬性設置為YES爆安,那么在導航條或者TabBar非透明的情況下,view的內容將會被他們遮擋(原點為0仔引,0)扔仓,該屬性僅僅對非透明的Bar控件有效。
    示例展示如下圖所示(代碼設置 navigationBar.translucent = NO 并且 extendedLayoutIncludesOpaqueBars = YES)


    非透明導航條遮擋內容效果展示.png
  • automaticallyAdjustsScrollViewInsets:意思是是否由系統(tǒng)自動調整滾動視圖的內邊距咖耘,默認為YES翘簇,意味著系統(tǒng)將會根據(jù)導航條和TabBar的情況自動增加上下內邊距以防止?jié)L動視圖的內容被Bar遮擋。

設置導航條或者TabBar背景圖片的注意事項

這里會詳細解釋官方文檔對translucent屬性的注釋儿倒,為什么放到這里才說版保?因為官方文檔對該屬性的解釋全部跟設置導航條或者TabBar的背景圖片有關!說明蘋果也知道夫否,這里坑很多彻犁,下面就來梳理一下吧。凰慈。汞幢。

translucent屬性的官方解釋
  • UINavigationBar/UITabBar的translucent屬性解釋:默認為YES,可以通過設置NO來強制使用非透明背景微谓,如果導航條使用自定義背景圖片森篷,那么默認情況該屬性的值由圖片的alpha(透明度)決定,如果alpha的透明度小于1.0值為YES豺型。如果手動設置translucent為YES并且使用自定義不透明圖片仲智,那么會自動設置系統(tǒng)透明度(小于1.0)在這個圖片上。如果手動設置translucent為NO并且使用自定義帶透明度(透明度小于0)的圖片姻氨,那么系統(tǒng)會展示這張背景圖片钓辆,只不過這張圖片會使用事先確定的barTintColor進行不透明處理,若barTintColor為空,則會使用UIBarStyleBlack(黑色)或者UIBarStyleDefault(白色)岩馍。
設置導航欄背景圖片透明度問題
  • 如果背景圖片沒有透明度,系統(tǒng)會自動把導航控制器的棧頂控制器的view的Y值增加64抖韩,如果沒有透明度蛀恩,則不會增加。
  • 這一情況的圖片必須是imageSet格式的茂浮,并且圖片的透明度為1(不透明)双谆,系統(tǒng)才會去調整。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末席揽,一起剝皮案震驚了整個濱河市顽馋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌幌羞,老刑警劉巖寸谜,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異属桦,居然都是意外死亡熊痴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門聂宾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來果善,“玉大人,你說我怎么就攤上這事系谐〗砩拢” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵纪他,是天一觀的道長鄙煤。 經(jīng)常有香客問我,道長止喷,這世上最難降的妖魔是什么馆类? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮弹谁,結果婚禮上乾巧,老公的妹妹穿的比我還像新娘。我一直安慰自己预愤,他們只是感情好沟于,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著植康,像睡著了一般旷太。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天供璧,我揣著相機與錄音存崖,去河邊找鬼。 笑死睡毒,一個胖子當著我的面吹牛来惧,可吹牛的內容都是我干的。 我是一名探鬼主播演顾,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼供搀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了钠至?” 一聲冷哼從身側響起葛虐,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棉钧,沒想到半個月后屿脐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡掰盘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年摄悯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愧捕。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡奢驯,死狀恐怖,靈堂內的尸體忽然破棺而出次绘,到底是詐尸還是另有隱情瘪阁,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布邮偎,位于F島的核電站管跺,受9級特大地震影響,放射性物質發(fā)生泄漏禾进。R本人自食惡果不足惜豁跑,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望泻云。 院中可真熱鬧艇拍,春花似錦、人聲如沸宠纯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽婆瓜。三九已至快集,卻和暖如春贡羔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背个初。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工乖寒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人院溺。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓宵统,卻偏偏與公主長得像,于是被迫代替她去往敵國和親覆获。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容