概述
iOS11 中增加了 SafeArea 的概念倔矾,規(guī)定了蘋果建議的最合適的內(nèi)容展示區(qū)域咽白。
在iPhoneX中
- 狀態(tài)欄高度由 20pt 變?yōu)?44pt
- 導(dǎo)航欄以上高度由 64pt 變?yōu)?88pt
- 底部工具欄需要為 home indicator 留出 34pt 邊距
Frame 布局
UIView
UIView 中新增了以下屬性绞佩,我們可以利用此屬性來知道當(dāng)前 view 所需要下移以及加高的值飞蚓。
@property(nonatomic, readonly) UIEdgeInsets safeAreaInsets;
- 通常在 - (void)layoutSubviews 方法中使用 safeAreaInsets 布局
- (void)layoutSubviews {
[super layoutSubviews];
if (@available(iOS 11.0, *)) {
self.titleLabel.frame = CGRectMake(0, self.view.safeAreaInsets.top, 100, 100);
}
}
UIViewController
UIViewController 中新增了以下屬性來設(shè)置 safeAreaInsets
@property(nonatomic) UIEdgeInsets additionalSafeAreaInsets;
viewSafeAreaInsetsDidChange 的調(diào)用順序:
- (void)viewDidLoad
- (void)viewWillAppear
- (void)viewSafeAreaInsetsDidChange // safeArea 改變時(shí)調(diào)用
- (void)viewWillLayoutSubviews
- (void)viewDidLayoutSubviews
- (void)viewDidAppear
- 只有在調(diào)用 viewSafeAreaInsetsDidChange 及以后的方法才能獲得 view 和 Controller 的UIEdgeInsets(44,0,34,0)仗处。所以在 viewDidLoad 中根據(jù) safeAreaInsets 設(shè)置界面會(huì)有問題胳喷。
AutoLayout 布局
UIView 中還有一個(gè)用于 AutoLayout 布局的屬性
@property(nonatomic, readonly, strong) UILayoutGuide *safeAreaLayoutGuide;
- Masonry 1.1.0 已更新了 SafeArea 相關(guān)的用法
// 盡量使用這種方式
[self.label mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.penBtn.mas_left);
make.top.equalTo(self.view.mas_top).priorityMedium();
if (@available(iOS 11.0, *)) {
make.top.greaterThanOrEqualTo(self.view.mas_safeAreaLayoutGuideTop);
}
}];
// 如果 iphoneX 和其他機(jī)型偏移量不同且無法用 SafeArea 相關(guān)屬性解決,再用這樣的方式
[view mas_makeConstraints:^(MASConstraintMaker *make) {
if ([UIDevice awe_isIPhoneX]) {
if (@available(iOS 11.0, *)) {
make.top.greaterThanOrEqualTo(self.view.mas_safeAreaLayoutGuideTop).offset(12);
}
} else {
make.top.equalTo(self.view).offset(30);
}
make.right.lessThanOrEqualTo(self.view.mas_left).offset(10);
make.centerX.equalTo(self.view);
}];
一些Tips
- 適配時(shí)盡量使用 SafeArea 相關(guān)的屬性席吴,不要簡單粗暴的直接指定偏移量的大小
// 錯(cuò)誤示范6慕帷!孝冒!不要這樣搞<硪Α!迈倍!
[self.cancelButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(@(74));
make.height.equalTo(@(74));
if ([UIDevice awe_isIPhoneX]) {
make.top.equalTo(@(20));
} else {
make.top.equalTo(@(0));
}
make.right.equalTo(@(0));
}];
// 這樣才是對(duì)噠~伤靠!
[self.cancelButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(@(74));
make.height.equalTo(@(74));
make.right.equalTo(@(0));
make.top.equalTo(self.view.mas_top).priorityMedium();
if (@available(iOS 11.0, *)) {
make.top.greaterThanOrEqualTo(self.view.mas_safeAreaLayoutGuideTop);
}
}];
- 常用的宏
- 一般用于 frame 的改變捣域,AutoLayout 中盡量不要用
#define STATUS_BAR_HEIGHT [UIApplication sharedApplication].statusBarFrame.size.height
#define STATUS_BAR_NORMAL_HEIGHT ([UIDevice isIPhoneX] ? STATUS_BAR_HEIGHT : 20)
#define TAB_BAR_HEIGHT 49
#define NAVIGATION_BAR_HEIGHT ([UIDevice isIPhoneX] ? 88 : 64)
#define NAVIGATION_BAR_OFFSET ([UIDevice isIPhoneX] ? 24 : 0)
#define IPHONE_X_BOTTOM_OFFSET ([UIDevice isIPhoneX] ? 34 : 0)
- 判斷機(jī)型 : 不到萬不得已不要用這個(gè)方法啼染!不到萬不得已不要用這個(gè)方法!不到萬不得已不要用這個(gè)方法焕梅!
#import <sys/utsname.h>
+ (BOOL)isIPhoneX {
struct utsname systemInfo;
uname(&systemInfo);
NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
if ([platform isEqualToString:@"iPhone10,3"] || [platform isEqualToString:@"iPhone10,6"]) {
return YES;
}
return NO;
}