版本記錄
版本號 | 時間 |
---|---|
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));
我們先說一下以前的topLayoutGuide
和 bottomLayoutGuide
都是干什么的。
topLayoutGuide
和 bottomLayoutGuide
兩個屬性來描述不希望被透明的狀態(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è)置如下約束:
下面在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 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í)際效果
點(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ù)的事情了。
參考文章
后記
本篇主要介紹了Safe Area的由來以及其簡單的使用桨菜,可以說是很基礎(chǔ)的東西豁状,感興趣的給個贊或者關(guān)注,謝謝~~~