iOS 11系統發佈後, UIView多了幾個安全區域相關的屬性和方法, 用於界面適配, 如:safeAreaInsets, safeAreaLayoutGuide,insetsLayoutMarginsFromSafeArea,以及safeAreaInsetsDidChange方法;
理解:
在iOS11前, 作界面適配時, 若是界面上有導航欄時, 若是想作到界面不被導航欄遮蓋住, 須要在設置約束時, 可將frame.origin.y設置爲0,如:
self.bgView.frame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height);
(bgView是一個控件)
當iPhoneX系列沒發佈前, 其餘全部iPhone機型的導航欄, 狀態欄, tabbar欄, 高度都是同樣, 作適配的時候很簡單.可是iPhoneX系列發佈後, 出現了新的狀態欄, tabbar欄高度, 致使適配工做量加大,因此官方新增了safeAreaInsets等屬性,方便界面適配.
複製代碼
safeArea是指沒有被狀態欄, 導航欄, tabbar欄, toolbars, 或其餘視圖控制器遮蓋的區域, 經過safeAreaInsets能夠獲取到視圖的安全距離. 可是若是一個view沒有在視圖層次結構中或未在屏幕上顯示, 則safeAreaInsets爲0;
示例一: 在iPhone6s上測試一個控件的安全距離(iOS系統爲12.0)
- (void)viewDidLoad {
[super viewDidLoad];
if (@available(iOS 11.0, *)) {//viewDidLoad
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (@available(iOS 11.0, *)) {
NSLog(@"2 --- viewWillAppear");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
if (@available(iOS 11.0, *)) {
NSLog(@"3 --- viewSafeAreaInsetsDidChange");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
if (@available(iOS 11.0, *)) {//viewWillLayoutSubviews
NSLog(@"4 --- viewWillLayoutSubviews");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (@available(iOS 11.0, *)) {//viewDidLayoutSubviews
NSLog(@"5 --- viewDidLayoutSubviews");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (@available(iOS 11.0, *)) {
NSLog(@"6 --- viewDidAppear");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
輸出結果:
1 --- viewDidLoad
self.view.safeAreaInsets.top = 0.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 0.000000
self.view.safeAreaInsets.right = 0.000000
2 --- viewWillAppear
self.view.safeAreaInsets.top = 0.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 0.000000
self.view.safeAreaInsets.right = 0.000000
3 --- viewSafeAreaInsetsDidChange
self.view.safeAreaInsets.top = 64.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 49.000000
self.view.safeAreaInsets.right = 0.000000
4 --- viewWillLayoutSubviews
self.view.safeAreaInsets.top = 64.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 49.000000
self.view.safeAreaInsets.right = 0.000000
5 --- viewDidLayoutSubviews
self.view.safeAreaInsets.top = 64.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 49.000000
self.view.safeAreaInsets.right = 0.000000
6 --- viewDidAppear
self.view.safeAreaInsets.top = 64.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 49.000000
self.view.safeAreaInsets.right = 0.000000
示例二: 在iPhone6s上測試一個控件的安全距離(iOS系統爲9.3)
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1 --- viewDidLoad");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
結果: 代碼直接崩潰, 報錯信息:-[UIView safeAreaInsets]: unrecognized selector sent to instance 0x7fdc674467c0
示例三: 在iPhoneX上測試一個控件的安全距離
- (void)viewDidLoad {
[super viewDidLoad];
if (@available(iOS 11.0, *)) {
NSLog(@"1 --- viewDidLoad");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (@available(iOS 11.0, *)) {
NSLog(@"2 --- viewWillAppear");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
if (@available(iOS 11.0, *)) {
NSLog(@"3 --- viewSafeAreaInsetsDidChange");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
if (@available(iOS 11.0, *)) {//viewWillLayoutSubviews
NSLog(@"4 --- viewWillLayoutSubviews");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (@available(iOS 11.0, *)) {
NSLog(@"5 --- viewDidLayoutSubviews");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (@available(iOS 11.0, *)) {
NSLog(@"6 --- viewDidAppear");
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
}
}
輸出結果:
1 --- viewDidLoad
self.view.safeAreaInsets.top = 0.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 0.000000
self.view.safeAreaInsets.right = 0.000000
2 --- viewWillAppear
self.view.safeAreaInsets.top = 0.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 0.000000
self.view.safeAreaInsets.right = 0.000000
3 --- viewSafeAreaInsetsDidChange
self.view.safeAreaInsets.top = 88.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 83.000000
self.view.safeAreaInsets.right = 0.000000
4 --- viewWillLayoutSubviews
self.view.safeAreaInsets.top = 88.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 83.000000
self.view.safeAreaInsets.right = 0.000000
5 --- viewDidLayoutSubviews
self.view.safeAreaInsets.top = 88.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 83.000000
self.view.safeAreaInsets.right = 0.000000
6 --- viewDidAppear
self.view.safeAreaInsets.top = 88.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 83.000000
self.view.safeAreaInsets.right = 0.000000
小結:
(1)view沒有在視圖層次結構中或未在屏幕上顯示時, safeAreaInsets爲0;
(2)矩形或劉海屏手機均有安全距離, 只要iOS系統大於或等於11;
(3)若是安全距離存在, 能夠經過safeAreaInsets獲取到視圖的安全距離;
複製代碼
對於一個viewController的root view, safeArea指的是未被狀態欄、一些可見的bars和經過additionalSafeAreaInsets屬性設置的值遮蓋的區域; 安全
(圖片來自於網絡)對於在視圖層次結構中的其餘視圖, safeArea指的是未被狀態欄、navigation bars、tabbar、toolbars或其餘視圖控制器遮蓋的區域。 例如: 若是一個視圖徹底在它父視圖的範圍內, 那麼safeAreaInsets爲0;若是其超出父視圖的安全範圍,那麼safeAreaInsets按照被遮住的大小計算。bash
示例一:vc的rootView是redView, redView有個subView是yellowView, 當yellowView不處於redView的安全區域以內時: 網絡
yellowView是redView的子控件- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (@available(iOS 11.0, *)) {
//打印redView的安全距離(redView就是vc的root View)
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
//打印yellowView的安全距離
NSLog(@"self.yellowView.safeAreaInsets.top = %f",self.yellowView.safeAreaInsets.top);
NSLog(@"self.yellowView.safeAreaInsets.left = %f",self.yellowView.safeAreaInsets.left);
NSLog(@"self.yellowView.safeAreaInsets.bottom = %f",self.yellowView.safeAreaInsets.bottom);
NSLog(@"self.yellowView.safeAreaInsets.right = %f",self.yellowView.safeAreaInsets.right);
}
}
輸出結果:
self.view.safeAreaInsets.top = 44.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 34.000000
self.view.safeAreaInsets.right = 0.000000
self.yellowView.safeAreaInsets.top = 44.000000
self.yellowView.safeAreaInsets.left = 0.000000
self.yellowView.safeAreaInsets.bottom = 34.000000
self.yellowView.safeAreaInsets.right = 0.000000
複製代碼
從輸出結果能夠看出,若是子視圖超出父視圖的安全範圍, 那麼safeAreaInsets按照被遮住的大小計算;ide
示例二:vc的rootView是redView, redView有個subView是yellowView, 當yellowView處於redView的安全區域以內時: 測試
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (@available(iOS 11.0, *)) {
NSLog(@"self.view.safeAreaInsets.top = %f",self.view.safeAreaInsets.top);
NSLog(@"self.view.safeAreaInsets.left = %f",self.view.safeAreaInsets.left);
NSLog(@"self.view.safeAreaInsets.bottom = %f",self.view.safeAreaInsets.bottom);
NSLog(@"self.view.safeAreaInsets.right = %f",self.view.safeAreaInsets.right);
NSLog(@"self.yellowView.safeAreaInsets.top = %f",self.yellowView.safeAreaInsets.top);
NSLog(@"self.yellowView.safeAreaInsets.left = %f",self.yellowView.safeAreaInsets.left);
NSLog(@"self.yellowView.safeAreaInsets.bottom = %f",self.yellowView.safeAreaInsets.bottom);
NSLog(@"self.yellowView.safeAreaInsets.right = %f",self.yellowView.safeAreaInsets.right);
}
}
輸出結果:
self.view.safeAreaInsets.top = 44.000000
self.view.safeAreaInsets.left = 0.000000
self.view.safeAreaInsets.bottom = 34.000000
self.view.safeAreaInsets.right = 0.000000
self.yellowView.safeAreaInsets.top = 0.000000
self.yellowView.safeAreaInsets.left = 0.000000
self.yellowView.safeAreaInsets.bottom = 0.000000
self.yellowView.safeAreaInsets.right = 0.000000
複製代碼
從輸出結果能夠看出視圖處於父視圖的安全區域中時, safeAreaInsets爲0;ui
若是對系統所提供的安全區域不滿意, 還能夠經過additionalSafeAreaInsets屬性來修改安全區域, 示例一:spa
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.redColor;
//修改安全區域
self.additionalSafeAreaInsets = UIEdgeInsetsMake(100, 30, 100, 40);
}
輸出結果:
self.view.safeAreaInsets.top = 144.000000
self.view.safeAreaInsets.left = 30.000000
self.view.safeAreaInsets.bottom = 134.000000
self.view.safeAreaInsets.right = 40.000000
複製代碼
從輸出接口能夠看出:
(1)經過additionalSafeAreaInsets能夠修改安全區域的大小;
(2)修改的安全區域的大小時,是在原來的安全區域的基礎上作出修改的;code
由此能夠看出,safeAreaInsets指的就是一個控件可見區域距離屏幕上下左右邊的距離。cdn
一個控制器從建立到界面顯示, 會依次調用如下方法:
- (void)viewDidLoad;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewSafeAreaInsetsDidChange;
- (void)viewWillLayoutSubviews;
- (void)viewDidLayoutSubviews;
- (void)viewDidAppear:(BOOL)animated;
在調用- viewSafeAreaInsetsDidChange方法時, 界面的safeAreaInsets值會被計算出來,在這個方法中能夠更改控件的位置;
複製代碼
參考:www.jianshu.com/p/671e70d8d…blog