快速自動化適配iPhone X

peterzeng 7年前發布 | 31K 次閱讀 iOS開發 移動開發

關于iPhone X的適配,主要需要做的工作點就是針對上下非安全區域的適配。

在iOS開發中,針對于布局存在 xib 與 代碼編輯 兩種方式。而這兩種方式又都支持 絕對布局 與 AutoLayout 兩種。

接下來本文將從xib、代碼編輯、絕對布局、Autolayout幾個布局方式來講解如何針對iPhone X做自動化適配

  • Xib布局

Xib的絕對布局并不靈活,如果想要通過特有因素更改View的Frame則需要通過屬性索引來實現。所以這里只針對Xib的AutoLayout來做講解

首先XCode9的Xib為我們提供了SafeAreaLayout選項,而這個選項并不支持iOS9以前的版本。

SafeAreaLayout

那么我們需要針對靠近底部或者頂部非安全區域的View做約束就可以達到理想效果,然而約束的值卻不能固定,你還需要兼顧非iPhone X的機型。

那么你可以從以下幾點中找到解決方法:

首先我們的布局文件如下:

  • 三個相同的Label位于控制器根View的底部

約束文件

首先,如果你是做一個新的頁面,那么在設置約束時,添加Constrain to margins屬性會幫你大忙,布局文件中的第二個Label就是使用Margin屬性進行布局。

Constrain to margins

首先,如果你有一個已經存在的頁面,而且已經設置好了約束的布局,那么你可以找到對應的約束屬性,勾選它的Relative to margin選項,將此約束屬性以指向相對于marigin。

  • 雙擊它 (╯>д<)╯?˙3˙?

約束屬性 Relative to margin入口

  • 勾選它 (╯>д<)╯?˙3˙?

Relative to margin

  • 接下來我們可以看到這三種布局產生的效果

  • 你可以通過布局視圖左下角的View as: (某某機型) ,選擇iPhone X機型來快速查看布局應用結果。

布局效果

  • 以及運行的效果

運行效果

  • 可以看到,基礎約束并不會對iPhone X底部的非安全區域進行適配,而Constrain to margins 與Relative to margin作用下的約束,則可以完美的適應iPhone X。

  • 使用代碼布局

代碼布局依然可以通AutoLayout進行布局,同時也可以通過分支判斷來進行絕對布局。

  • AutoLayout

1.如果你需要使用原生的API來進行AutoLayout布局,那么你可以使用NSLayoutAttributeBottomMargin作為Bottom的約束枚舉值

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:self.leftLabel >attribute:NSLayoutAttributeBottomMargin relatedBy:NSLayoutRelationEqual toItem:self.rightLabel >attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
[self.view addConstraint:constraint];

2.如果你的Autolayout是通過Masonry進行編輯的,那么你只需要更改底部約束

  • 在更早的Masonry版本中

由:

make.bottom.equalTo(self.view.mas_bottom);

改為:

make.bottom.equalTo(self.view.mas_bottomMargin);
[self.rightLabel mas_makeConstraints:^(MASConstraintMaker *make) {
       make.height.mas_equalTo(100);
       make.left.equalTo(self.leftLabel.mas_right);
       make.right.equalTo(self.view);
       make.bottom.equalTo(self.view.mas_bottomMargin);
}];
  • 在新的Masonry版本中,當編譯器提醒你找不到mas_bottomMargin時,通過:

由:

make.bottom.equalTo(self.view.mas_bottom);

改為:

make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
[self.rightLabel mas_makeConstraints:^(MASConstraintMaker *make) {
       make.height.mas_equalTo(100);
       make.left.equalTo(self.leftLabel.mas_right);
       make.right.equalTo(self.view);
       if (@available(iOS 11.0, *)) {
           make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
       } else {
           make.bottom.equalTo(self.view.mas_bottom);
       }
}];
  • 完整代碼如下

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"代碼布局";
    [self initSubViews];
    [self initLayout];
}
- (void)initSubViews{
    UILabel *leftLabel = [[UILabel alloc] init];
    leftLabel.text = @"基礎約束";
    leftLabel.numberOfLines = 0;
    leftLabel.textAlignment = NSTextAlignmentCenter;
    leftLabel.backgroundColor = [UIColor orangeColor];

    UILabel *rightLabel = [[UILabel alloc] init];
    rightLabel.text = @"Constrain to margins";
    rightLabel.numberOfLines = 0;
    rightLabel.textAlignment = NSTextAlignmentCenter;
    rightLabel.backgroundColor = [UIColor blueColor];

    [self.view addSubview:leftLabel];
    [self.view addSubview:rightLabel];

    self.leftLabel = leftLabel;
    self.rightLabel = rightLabel;
}
- (void)initLayout{
    [self.leftLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.mas_equalTo(100);
        make.width.equalTo(self.view).multipliedBy(0.5);
        make.left.equalTo(self.view);
        make.bottom.equalTo(self.view.mas_bottom);
    }];

    [self.rightLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.mas_equalTo(100);
        make.left.equalTo(self.leftLabel.mas_right);
        make.right.equalTo(self.view);
        if (@available(iOS 11.0, *)) {
            make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
        } else {
            make.bottom.equalTo(self.view.mas_bottom);
        }
    }];
}
  • 以及運行的效果

代碼布局

  • 使用代碼布局

  • 絕對布局

如果你需要使用代碼進行絕對布局,那么iOS11中View的safeAreaInsets屬性可以幫到你。因為safeAreaInsets最低支持iOS11的緣故,所以你需要加入版本判斷來使用。safeAreaInsets會給出你上下左右各個方位的非安全區域的大小,你可以通過這些值來設置自己的View的位置。

@property (nonatomic,readonly) UIEdgeInsets safeAreaInsets API_AVAILABLE(ios(11.0),tvos(11.0));
  • 在這里我準備了幾個宏供大家使用

#define IOS11_OR_LATER_SPACE(par) 
({
float space = 0.0;
if (@available(iOS 11.0, *))
space = par;
(space);
})
#define JF_KEY_WINDOW [UIApplication sharedApplication].keyWindow
#define JF_TOP_SPACE IOS11_OR_LATER_SPACE(JF_KEY_WINDOW.safeAreaInsets.top)
#define JF_TOP_ACTIVE_SPACE IOS11_OR_LATER_SPACE(MAX(0, JF_KEY_WINDOW.safeAreaInsets.top-20))
#define JF_BOTTOM_SPACE IOS11_OR_LATER_SPACE(JF_KEY_WINDOW.safeAreaInsets.bottom)
  • 宏里已經進行了版本判斷,如果你需要設置一個View置于控制器根View的底部,那么只需要通過

- (void)createView{
   UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
   view.backgroundColor = [UIColor redColor];
   [self.view addSubview:view];

   self.bottomView = view;
}
- (void)viewDidLayoutSubviews{
   [super viewDidLayoutSubviews];

   CGRect frame = self.bottomView.frame;
   frame.origin.y = self.view.bounds.size.height - frame.size.height - JF_BOTTOM_SPACE;
   self.bottomView.frame = frame;
}

以上代碼,來減去非安全區的位置即可

PS:safeAreaInsets還可以用來進行設置連接于View邊緣的ScrollView的Insets額外滑動區域

Demo下載: https://github.com/Jiang-Fallen/LayoutiPhoneX

聯系郵箱:Jiang.Fallen@gmail.com

 

來自: http://www.jianshu.com/p/263e08f1ad6e

 

 本文由用戶 peterzeng 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!