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的安全区域以内时: 网络
- (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