Safe Area解析(一) —— Safe Area由來及簡單使用(一)

版本記錄

版本號 時間
V1.0 2018.05.26

前言

Safe Area是iOS 9新出的么介,它的出現(xiàn)一定程度上解決了很多適配的問題娜遵,可以說解決了很多UI方面的問題,你再也不用擔(dān)心狀態(tài)欄是否被覆蓋壤短,特別是iphone X出現(xiàn)以后设拟,狀態(tài)欄和底部都留有和其他機(jī)型不同的高度慨仿,這給適配帶來更多的麻煩,但是Safe Area預(yù)留出來安全區(qū)域纳胧,可以讓你對UI的適配無后顧之憂镰吆。感興趣的可以看我上面寫的幾篇文章。

Safe Area是什么跑慕?

在說Safe Area之前万皿,我們先一起看兩個東西:

@interface UIViewController (UILayoutSupport)
// These objects may be used as layout items in the NSLayoutConstraint API
@property(nonatomic,readonly,strong) id<UILayoutSupport> topLayoutGuide API_DEPRECATED("Use view.safeAreaLayoutGuide.topAnchor instead of topLayoutGuide.bottomAnchor", ios(7.0,11.0), tvos(7.0,11.0));
@property(nonatomic,readonly,strong) id<UILayoutSupport> bottomLayoutGuide API_DEPRECATED("Use view.safeAreaLayoutGuide.bottomAnchor instead of bottomLayoutGuide.topAnchor", ios(7.0,11.0), tvos(7.0,11.0));

/* Custom container UIViewController subclasses can use this property to add to the overlay
 that UIViewController calculates for the safeAreaInsets for contained view controllers.
 */
@property(nonatomic) UIEdgeInsets additionalSafeAreaInsets API_AVAILABLE(ios(11.0), tvos(11.0));

/* Minimum layoutMargins for the view determined by the view controller from context and hardware information.
 The view controller's view will respect these minimums unless viewRespectsSystemMinimumLayoutMargins
 (which defaults to YES) is set to NO.
 */
@property(nonatomic,readonly) NSDirectionalEdgeInsets systemMinimumLayoutMargins API_AVAILABLE(ios(11.0), tvos(11.0));

/* Default YES. The return value of the view's layoutMargins and directionalLayoutMargins properties will have
 values no smaller than the systemMinimumLayoutMargins. Set to NO for full customizability of the view's
 layoutMargins.
 */
@property(nonatomic) BOOL viewRespectsSystemMinimumLayoutMargins API_AVAILABLE(ios(11.0), tvos(11.0));

- (void)viewLayoutMarginsDidChange NS_REQUIRES_SUPER API_AVAILABLE(ios(11.0), tvos(11.0));
- (void)viewSafeAreaInsetsDidChange NS_REQUIRES_SUPER API_AVAILABLE(ios(11.0), tvos(11.0));

@end

上面就是UIViewController里面關(guān)于布局的一個分類,大家也看到了

// These objects may be used as layout items in the NSLayoutConstraint API
@property(nonatomic,readonly,strong) id<UILayoutSupport> topLayoutGuide API_DEPRECATED("Use view.safeAreaLayoutGuide.topAnchor instead of topLayoutGuide.bottomAnchor", ios(7.0,11.0), tvos(7.0,11.0));
@property(nonatomic,readonly,strong) id<UILayoutSupport> bottomLayoutGuide API_DEPRECATED("Use view.safeAreaLayoutGuide.bottomAnchor instead of bottomLayoutGuide.topAnchor", ios(7.0,11.0), tvos(7.0,11.0));

上面這兩個是iOS 7出來的核行,iOS11已經(jīng)被廢棄了牢硅,替換他們的就是Safe Area,上面說的就是被view.safeAreaLayoutGuide.bottomAnchor替代芝雪,那個是在UIView的API中减余。

/* -layoutMargins returns a set of insets from the edge of the view's bounds that denote a default spacing for laying out content.
 If preservesSuperviewLayoutMargins is YES, margins cascade down the view tree, adjusting for geometry offsets, so that setting
 the left value of layoutMargins on a superview will affect the left value of layoutMargins for subviews positioned close to the
 left edge of their superview's bounds
   If your view subclass uses layoutMargins in its layout or drawing, override -layoutMarginsDidChange in order to refresh your 
 view if the margins change.
   On iOS 11.0 and later, please support both user interface layout directions by setting the directionalLayoutMargins property
 instead of the layoutMargins property. After setting the directionalLayoutMargins property, the values in the left and right
 fields of the layoutMargins property will depend on the user interface layout direction.
 */
@property (nonatomic) UIEdgeInsets layoutMargins NS_AVAILABLE_IOS(8_0);

/* directionalLayoutMargins.leading is used on the left when the user interface direction is LTR and on the right for RTL.
 Vice versa for directionalLayoutMargins.trailing.
 */
@property (nonatomic) NSDirectionalEdgeInsets directionalLayoutMargins API_AVAILABLE(ios(11.0),tvos(11.0));

@property (nonatomic) BOOL preservesSuperviewLayoutMargins NS_AVAILABLE_IOS(8_0); // default is NO - set to enable pass-through or cascading behavior of margins from this view’s parent to its children
@property (nonatomic) BOOL insetsLayoutMarginsFromSafeArea API_AVAILABLE(ios(11.0),tvos(11.0));  // Default: YES

- (void)layoutMarginsDidChange NS_AVAILABLE_IOS(8_0);

@property (nonatomic,readonly) UIEdgeInsets safeAreaInsets API_AVAILABLE(ios(11.0),tvos(11.0));
- (void)safeAreaInsetsDidChange API_AVAILABLE(ios(11.0),tvos(11.0));

/* The edges of this guide are constrained to equal the edges of the view inset by the layoutMargins
 */
@property(readonly,strong) UILayoutGuide *layoutMarginsGuide NS_AVAILABLE_IOS(9_0);

/// This content guide provides a layout area that you can use to place text and related content whose width should generally be constrained to a size that is easy for the user to read. This guide provides a centered region that you can place content within to get this behavior for this view.
@property (nonatomic, readonly, strong) UILayoutGuide *readableContentGuide  NS_AVAILABLE_IOS(9_0);

/* The top of the safeAreaLayoutGuide indicates the unobscured top edge of the view (e.g, not behind
 the status bar or navigation bar, if present). Similarly for the other edges.
 */
@property(nonatomic,readonly,strong) UILayoutGuide *safeAreaLayoutGuide API_AVAILABLE(ios(11.0),tvos(11.0));

我們先說一下以前的topLayoutGuidebottomLayoutGuide都是干什么的。

topLayoutGuidebottomLayoutGuide 兩個屬性來描述不希望被透明的狀態(tài)欄或者導(dǎo)航欄遮擋的最高位置惩系。這個屬性的值是一個length屬性( topLayoutGuide.length)位岔。 這個值可能由當(dāng)前的ViewController或者 NavigationController 或者TabbarController決定。

一個獨(dú)立的ViewController堡牡,不包含于任何其他的ViewController抒抬。如果狀態(tài)欄可見,topLayoutGuide表示狀態(tài)欄的底部悴侵,否則表示這個ViewController的上邊緣瞧剖。包含于其他ViewController的ViewController不對這個屬性起決定作用,而是由容器ViewController決定這個屬性的含義可免。

  • 如果導(dǎo)航欄(Navigation Bar)可見抓于,topLayoutGuide表示導(dǎo)航欄的底部

  • 如果狀態(tài)欄可見,topLayoutGuide表示狀態(tài)欄的底部浇借。

  • 如果都不可見捉撮,表示ViewController的上邊緣。

iOS 11以后為了獲得更好的適配體驗(yàn)就棄用了這兩個屬性妇垢,更改為Safe Area相關(guān)的概念和屬性巾遭。蘋果建議:不要把VC放在Safe Area之外。


Safe Area簡單應(yīng)用

先看一個最簡單的應(yīng)用闯估,在根view上脫上一個子視圖灼舍,設(shè)置如下約束:

設(shè)置約束
視圖結(jié)構(gòu)

下面在6s模擬器上運(yùn)行,如下所示:

NSLog(@"safeAreaInsets = %lf, %lf, %lf, %lf", self.testView.safeAreaInsets.left, self.testView.safeAreaInsets.right, self.testView.safeAreaInsets.top, self.testView.safeAreaInsets.bottom);
NSLog(@"self.testView = %@", self.testView);

看運(yùn)行結(jié)果

2018-05-26 14:50:56.158103+0800 JJWebImage[64139:1049305] safeAreaInsets = 0.000000, 0.000000, 0.000000, 0.000000
2018-05-26 14:50:56.158496+0800 JJWebImage[64139:1049305] self.testView = <UIView: 0x7ff272f096f0; frame = (0 20; 375 647); autoresize = RM+BM; layer = <CALayer: 0x60c00003c3e0>>

可見safeAreaInsets上左下右的間距均為0涨薪,并且預(yù)留出來上邊20狀態(tài)欄的高度骑素。

具體效果如下所示:

iphone 6s效果

下面換成iPhone X看一下輸出和實(shí)際效果

先看輸出

2018-05-26 15:07:33.072648+0800 JJWebImage[64417:1065730] safeAreaInsets = 0.000000, 0.000000, 0.000000, 0.000000
2018-05-26 15:07:33.072999+0800 JJWebImage[64417:1065730] self.testView = <UIView: 0x7feb48c1a8f0; frame = (0 44; 375 734); autoresize = RM+BM; layer = <CALayer: 0x600000037180>>

再看實(shí)際效果

iphone X

點(diǎn)擊testView可見其frame及在父視圖中的位置。

可見其頂部預(yù)留大小為44個點(diǎn)刚夺,底部預(yù)留大小為34個點(diǎn)献丑。擴(kuò)展下:iPhone X豎屏?xí)r占滿整個屏幕的控制器的view的safeAreaInsets(44末捣,0,34创橄,0)箩做,橫屏是(0,44妥畏,21邦邦,44),inset后的區(qū)域正好是safeAreaLayoutGuide區(qū)域咖熟。


總結(jié)

  • Xcode9 用 IB 可以看得出來, safe area 到處都是了圃酵。理解起來很簡單。就是系統(tǒng)對每個 View 都添加了 safe area馍管, 這個區(qū)域的大小郭赐,是否跟 view 的大小相同是系統(tǒng)來決定的。在這個 View 上的布局只需要相對于 safe area 就可以了确沸。每個 View 的 safe area 都可以通過 iOS 11 新增的 API safeAreaInsets 或者safeAreaLayoutGuide獲取捌锭。

  • 對與 UIViewController 來說新增了additionalSafeAreaInsets這個屬性, 用來管理有 tabbar 或者 navigation bar 的情況下額外的情況。

  • scrollView 只需要設(shè)置contentInsetAdjustmentBehavior就可以很容易的適配iPhoneX罗捎。

  • tableView 只需要在cell header footer等設(shè)置約束的時候相對于 safe area 來做观谦。

  • collection view來說修改sectionInsetReference.safeArea就可以做大多數(shù)的事情了。

參考文章

1. 最近很火的 Safe Area 到底是什么

后記

本篇主要介紹了Safe Area的由來以及其簡單的使用桨菜,可以說是很基礎(chǔ)的東西豁状,感興趣的給個贊或者關(guān)注,謝謝~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倒得,一起剝皮案震驚了整個濱河市泻红,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌霞掺,老刑警劉巖谊路,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異菩彬,居然都是意外死亡缠劝,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門骗灶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惨恭,“玉大人,你說我怎么就攤上這事耙旦⊥严郏” “怎么了错英?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵织狐,是天一觀的道長。 經(jīng)常有香客問我助泽,道長琴昆,這世上最難降的妖魔是什么氓鄙? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮业舍,結(jié)果婚禮上抖拦,老公的妹妹穿的比我還像新娘。我一直安慰自己舷暮,他們只是感情好态罪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著下面,像睡著了一般复颈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沥割,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天耗啦,我揣著相機(jī)與錄音,去河邊找鬼机杜。 笑死帜讲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的椒拗。 我是一名探鬼主播似将,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蚀苛!你這毒婦竟也來了在验?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤枉阵,失蹤者是張志新(化名)和其女友劉穎译红,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兴溜,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侦厚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拙徽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刨沦。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖膘怕,靈堂內(nèi)的尸體忽然破棺而出想诅,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布来破,位于F島的核電站篮灼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏徘禁。R本人自食惡果不足惜诅诱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望送朱。 院中可真熱鬧娘荡,春花似錦、人聲如沸驶沼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽回怜。三九已至大年,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹉戚,已是汗流浹背鲜戒。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抹凳,地道東北人遏餐。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像赢底,于是被迫代替她去往敵國和親失都。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容