iOS頁面適配的正確姿勢


我這里講解使用的是Masonry,我假設你對約束有一定的了解。

隨着iPhone X的出現,iOS頁面的適配似乎也麻煩了起來,我見得最多的就是通過某種手段判斷機型或者獲取導航欄的高度,然后計算寬高。我不說這種方法好不好,因為它也能解決你目前的問題,但不是我喜歡的方式。

在正式開始之前,我先介紹幾個重要的知識:

1.topLayoutGuide和bottomLayoutGuide

這兩個屬性屬於UIViewController,topLayoutGuide主要就是指導航欄,狀態欄;bottomLayoutGuide主要指TabBar(劉海手機上也可指代底部黑條的部分),主要就是為了讓你使用約束的時候對頂部和底部有個參考,避免視圖上的內容被遮擋。

2.safeAreaLayoutGuide

這個屬性是iOS11才有的,也就是蘋果對於劉海屏給出的一種解決方案。它和1中的兩個屬性作用類似,由於屬於UIView類,不受限於UIViewController,所以在靈活性上更強。

從它的名字可以看出來,它是一種安全區域的參考,那么安全區域指哪塊呢?如下圖:

 

從上面的圖可以看得出來,安全區域可以保證我們的內容不被遮擋。

 

3. Masonry中相應的屬性

既然我們用Masonry,我們就需要知道與系統中對應的屬性是哪些:

//  安全區域對應的屬性 
@property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuide NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideLeading NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideTrailing NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideLeft NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideRight NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideTop NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideBottom NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideWidth NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideHeight NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideCenterX NS_AVAILABLE_IOS(11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_safeAreaLayoutGuideCenterY NS_AVAILABLE_IOS(11.0);
// 一般參考對應的屬性
@property (nonatomic, strong, readonly) MASViewAttribute *mas_topLayoutGuide NS_DEPRECATED_IOS(8.0, 11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomLayoutGuide NS_DEPRECATED_IOS(8.0, 11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_topLayoutGuideTop NS_DEPRECATED_IOS(8.0, 11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_topLayoutGuideBottom NS_DEPRECATED_IOS(8.0, 11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomLayoutGuideTop NS_DEPRECATED_IOS(8.0, 11.0); @property (nonatomic, strong, readonly) MASViewAttribute *mas_bottomLayoutGuideBottom NS_DEPRECATED_IOS(8.0, 11.0);

從名字中我們就能很清晰的識別出來

4.實戰

我們創建一個簡單的工程,初始頁面是一個帶有導航欄的紅色視圖控制器,如下圖所示:

  

我們將在這上面創建一個綠色的視圖,來具體看一下上面1和2提到的屬性怎么去用。

首先我們不使用上面的屬性來設置約束,代碼如下:

 UIView *view = [[UIView alloc] init];
 view.backgroundColor = [UIColor greenColor];
 [self.view addSubview:view];
 [view mas_makeConstraints:^(MASConstraintMaker *make) {
     make.top.equalTo(self.view.mas_top);
     make.height.equalTo(@200);
     make.left.right.equalTo(self.view);
 }];
    

我們只是簡單的設置了子視圖和父視圖之間的約束,似乎看起來沒什么問題,但是當我們運行一下就會發現,不好的事情發生了。

我們的綠色視圖竟然被導航欄遮住了一部分,這不是我們所希望了,因為將來有可能遮住我們的重要信息,也許你想着我們可以修改約束中make.top.equalTo(self.view.mas_top)為make.top.equalTo(self.view.mas_top).offset(88),讓其偏移88,但是這樣的壞處是顯而易見的,現在偏移88是沒問題的,但運行在沒有劉海的手機上又要改為偏移64,假如蘋果將來又出個神奇的手機,你是不是又要去判斷手機型號,然后偏移某一個值呢?從現在起,放棄這種適配方法吧(除了個別目的)。

我們把代碼修改為下面這個樣子 

    UIView *view = [[UIView alloc] init];

    view.backgroundColor = [UIColor greenColor];

    [self.view addSubview:view];

    [view mas_makeConstraints:^(MASConstraintMaker *make) {

        if (@available(iOS 11, *)) {

            make.top.equalTo(self.view.mas_safeAreaLayoutGuideTop);

        } else {

            make.top.equalTo(self.mas_topLayoutGuide);

        }

        make.height.equalTo(@200);

        make.left.right.equalTo(self.view);

    }];

這個代碼運行出來的效果如下,這樣的效果就是我們想要的,內容不會被導航欄遮擋。注意上面的代碼,有一個if語句,我們判斷了相應API能否在指定平台獲取,而這也是我們適配的關鍵,因為iPhone X以及之后出來的手機,系統肯定是在iOS11之上的(除了個別越獄的),所以我們適配劉海屏的思路就是判斷系統版本就夠了。

 

我們再來看看底部的適配,先上代碼

    UIView *view = [[UIView alloc] init];
    view.backgroundColor = [UIColor greenColor];
    [self.view addSubview:view];
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@200);
        make.left.right.equalTo(self.view);
        make.bottom.equalTo(self.view.mas_bottom);
    }];

這種運行出來的效果為:

 

 

 

也許你認為這樣沒什么不好,你說得對,這樣是沒什么不好,但是底部大約有32的距離是系統不希望我們使用的,因為怕和系統的手勢沖突。所以這里我們也是要用到底部的參考和安全區域的參考

    UIView *view = [[UIView alloc] init];
    view.backgroundColor = [UIColor greenColor];
    [self.view addSubview:view];
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.height.equalTo(@200);
        make.left.right.equalTo(self.view);
        make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom); // 或者make.bottom.equalTo(self.mas_bottomLayoutGuide);
    }];

運行出來的效果如下,我們可以看到底部空出來了一段距離,這段距離就是系統不希望我們使用的。

 

 

4.總結

通過上面的例子,我們可以看到topLayoutGuide和bottomLayoutGuide與safeAreaLayoutGuide的作用區別不大,但是safeAreaLayoutGuide是在視圖類中就可以使用,更加方便了我們去做適配。通過參考安全區域或者之前的頂部布局參考,我們不在需要去判斷機型,也能達到頁面完美適配的目的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM