安全區(qū)域適配

iPhoneX安全區(qū)域
一、自適應(yīng)的UIView類別
使用 mas_bp_safeAreaLayoutGuideBottom 和 bp_safeAreaInsets 基本能解決iPhoneX適配問題。具體參考后面實(shí)例。
//
// UIView+SafeArea.h
//
#import <UIKit/UIKit.h>
#import <View+MASAdditions.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (SafeArea)
- (UIEdgeInsets)bp_safeAreaInsets;
- (UILayoutGuide *)bp_safeAreaLayoutGuide;
#pragma mark - Masonry
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuide;
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideTop;
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideBottom;
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideLeft;
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideRight;
@end
NS_ASSUME_NONNULL_END
//
// UIView+SafeArea.m
//
#import "UIView+SafeArea.h"
@implementation UIView (SafeArea)
- (UIEdgeInsets)bp_safeAreaInsets {
#if defined(__IPHONE_11_0)
if (@available(iOS 11, *)) {
return self.safeAreaInsets;
}
#endif
return UIEdgeInsetsZero;
}
/// UILayoutGuide可以被添加到View中,和View一樣可以設(shè)置各種約束,參與布局。但是它不會(huì)被渲染出來,不會(huì)響應(yīng)事件路由。
- (UILayoutGuide *)bp_safeAreaLayoutGuide {
#if defined(__IPHONE_11_0)
if (@available(iOS 11, *)) {
return self.safeAreaLayoutGuide;
}
#endif
static UILayoutGuide *normalGuide = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
normalGuide = [[UILayoutGuide alloc] init];
[self addLayoutGuide:normalGuide];
// 約束代碼,設(shè)置跟self大小完全一樣
[normalGuide.topAnchor constraintEqualToAnchor:self.topAnchor constant:statusBarAndNaviBarHeight].active = YES;
[normalGuide.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES;
[normalGuide.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[normalGuide.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-bottomSafeHeight].active = YES;
});
return normalGuide;
}
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuide {
#if defined(__IPHONE_11_0)
if (@available(iOS 11, *)) {
return self.mas_safeAreaLayoutGuide;
}
#endif
return self.mas_bottom;
}
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideTop {
#if defined(__IPHONE_11_0)
if (@available(iOS 11, *)) {
return self.mas_safeAreaLayoutGuideTop;
}
#endif
return self.mas_top;
}
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideBottom {
#if defined(__IPHONE_11_0)
if (@available(iOS 11, *)) {
return self.mas_safeAreaLayoutGuideBottom;
}
#endif
return self.mas_bottom;
}
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideLeft {
#if defined(__IPHONE_11_0)
if (@available(iOS 11, *)) {
return self.mas_safeAreaLayoutGuideLeft;
}
#endif
return self.mas_left;
}
- (MASViewAttribute *)mas_bp_safeAreaLayoutGuideRight {
#if defined(__IPHONE_11_0)
if (@available(iOS 11, *)) {
return self.mas_safeAreaLayoutGuideRight;
}
#endif
return self.mas_right;
}
@end
二、實(shí)際使用中 若以上不能達(dá)到要求,可以監(jiān)聽安全區(qū)域發(fā)生變化的回調(diào),重新設(shè)置約束
-----在控制器內(nèi)------
#pragma mark - SafeAreaInsetsDidChange
#if defined(__IPHONE_11_0)
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
NSLog(@"safeAreaInset %@", NSStringFromUIEdgeInsets(self.view.bp_safeAreaInsets));
// iPhoneX系列
// 豎屏 {44, 0, 34, 0}
// 橫屏 {0, 44, 21, 34}
// 其他機(jī)型
// {20, 0, 0, 0}
}
#endif
-----在UIView內(nèi)------
#pragma mark - SafeAreaInsetsDidChange
#if defined(__IPHONE_11_0)
- (void)safeAreaInsetsDidChange {
[super safeAreaInsetsDidChange];
NSLog(@"safeAreaInset %@", NSStringFromUIEdgeInsets(self.bp_safeAreaInsets));
}
#endif
- 安全區(qū)域發(fā)生變化并回調(diào) 要求是在iOS11系統(tǒng)以上,并且回調(diào)觸發(fā)在 viewDidAppear之后、layoutSubView之前,所以要注意 viewDidLoad 和 viewSafeAreaInsetsDidChange 兩個(gè)地方都要設(shè)置約束。在 viewDidLoad 設(shè)置約束是為了支持 iOS11以前系統(tǒng)。
- 隱藏系統(tǒng)導(dǎo)航欄時(shí): 非劉海屏,iOS11及之后系統(tǒng),safeAreaInsets.top = 20 , iOS11之前系統(tǒng) safeAreaInsets.top = 0 ;不隱藏系統(tǒng)導(dǎo)航欄時(shí) 都=0
實(shí)例參考
1、自定義navBar,隱藏系統(tǒng)導(dǎo)航欄 (適配頂部)
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:self.customNavBar];
[self.customNavBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.mas_equalTo(self.view);
make.height.mas_equalTo(HEIGHT_STATUSBAR + 44);
}];
}
/// 橫豎屏切換時(shí):狀態(tài)欄高度會(huì)發(fā)生變化
#ifdef __IPHONE_11_0
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
[self.customNavBar mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(self.view.bp_safeAreaInsets.top + 44);
}];
}
#endif
2、這個(gè)VC的整個(gè)頁面是個(gè)tableView,iPhoneX機(jī)器時(shí)底部34pt不建議用,特別是某些頁面底部是個(gè)UIButton時(shí) (適配底部)
///方法一:使用mas_bp_safeAreaLayoutGuideBottom
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:self.tableView];
[_tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.mas_equalTo(self.view);
make.bottom.mas_equalTo(self.view.mas_bp_safeAreaLayoutGuideBottom);
}];
}
///方法二:使用self.view.bp_safeAreaInsets.bottom
- (void)viewSafeAreaInsetsDidChange
{
[super viewSafeAreaInsetsDidChange];
[_tableView mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.mas_equalTo(self.view.mas_bottom).mas_offset(-self.view.bp_safeAreaInsets.bottom);
//如果需求是對(duì)齊到底部,只需刪除`bp_safeAreaInsets.bottom`
//make.bottom.mas_equalTo(self.view.mas_bottom);
}];
}