iOS 如何更好的適配異形屏(劉海屏)

通常我們在適配異形屏的時候,我們可能會使用 safeAreaInsets。使用時機不對的話,safeAreaInsets 的值還會存在問題。或許你可以使用 key windowsafeAreaInsets ,亦或者你可以通過重寫 func safeAreaInsetsDidChange() 方法,在合適的時候來修改布局,但這些操作總是比較麻煩,用起來并不舒服。

有沒有更好的方式呢???我們先來介紹兩個屬性。

layoutMargins

The default spacing to use when laying out content in the view.

iOS 8 新增,通過屬性名,我們就了解他是什么了,簡單來說就是布局中的邊距。

A view's margins

layoutMarginsGuide

A layout guide representing the view’s margins.

iOS 9 新增,你可以通過鏈接查看更多相關(guān)信息。

如何使用

下面將用過三個用例來總結(jié)用法。

示例一

let pinkView = UIView()
pinkView.backgroundColor = .systemPink
pinkView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pinkView)

view.addConstraints([
    NSLayoutConstraint(
        item: pinkView,
        attribute: .leftMargin,
        relatedBy: .equal,
        toItem: view,
        attribute: .leftMargin,
        multiplier: 1,
        constant: 0
    ),
    NSLayoutConstraint(
        item: pinkView,
        attribute: .rightMargin,
        relatedBy: .equal,
        toItem: view,
        attribute: .rightMargin,
        multiplier: 1,
        constant: 0
    ),
    NSLayoutConstraint(
        item: pinkView,
        attribute: .topMargin,
        relatedBy: .equal,
        toItem: view,
        attribute: .topMargin,
        multiplier: 1,
        constant: 0
    ),
    NSLayoutConstraint(
        item: pinkView,
        attribute: .bottomMargin,
        relatedBy: .equal,
        toItem: view,
        attribute: .bottomMargin,
        multiplier: 1,
        constant: 0
    )
])

view.layoutMargins = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)

可以使用 SnapKit 來簡化下代碼:

let pinkView = UIView()
pinkView.backgroundColor = .systemBlue
pinkView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pinkView)

pinkView.snp.makeConstraints {
    $0.edges.equalTo(self.view.layoutMarginsGuide)
}

layoutMargins = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)

self.view.layoutMarginsGuide 還可以替換成 self.view.snp.margins ,兩種方式等價。

同時,SnapKit 也可以單獨控制四個邊距,使用 leftMargin 、rightMargin、topMargin、bottomMargin 單獨控制。

用例一-豎屏

用例一-橫屏

可以從上面的圖片中看到,雖然我們設置四個邊距都是20pt。但是,實際在不同的機型上面的顯示,我們?nèi)庋劭梢姷倪吘嗍遣灰粯拥?,橫豎屏也是不一樣的。

這里就有必要提一下安全區(qū)域了,我們可以看到pinkView的視圖完全顯示在安全區(qū)域內(nèi)。事實上我們在設置布局的代碼時,并沒有考慮各種情況的安全區(qū)域,但是系統(tǒng)就是為我們加上了。我想,到這里,這種布局的好用之處就不言而喻了。

用例二

我們經(jīng)常會遇到在頁面底部添加一個工具條的需求,這個工具條需要做異形屏的適配。也就是在異形屏上,將其底部增加留白,使操作相關(guān)元素處在安全區(qū)域內(nèi)。

我們可以這樣來布局,達到適配的目的:

class BottomBar: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
      
        backgroundColor = .white

        layoutMargins = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)

        addSubview(button)

        button.snp.makeConstraints {
        $0.width.equalTo(90)
            $0.height.equalTo(36)
            $0.right.equalTo(self.snp.rightMargin)
            $0.top.equalTo(self.snp.topMargin)          
            $0.bottom.equalTo(self.snp.bottomMargin)
        }
    }
  ...
}

class ViewController: UIViewController {

    let bottomView = BottomBar()
  
    override func viewDidLoad() {
        super.viewDidLoad()
      
        view.addSubview(bottomView)
        bottomView.snp.makeConstraints {
            $0.left.bottom.right.equalTo(0)
        }
    }
}
用例二-豎屏
用例二-橫屏

可以看到底部工具條已經(jīng)適配好了,不需要我們做其他的操作??????。

上面的代碼,是通過一個尺寸固定的 button 將底部工具條撐滿,我們將 button 的底部約束設置成 $0.bottom.equalTo(self.snp.bottomMargin) ,設置容器視圖的 layoutMargins.bottom = 15 ,實際效果圖上面,系統(tǒng)已經(jīng)為我們自動加上了safeAreaInsets.bottom 。同時,橫屏狀態(tài)下,底部和右邊都加上了安全距離??????。

用例三

在用例二的基礎上,我們再加上一個工具條。

view.addSubview(bottomView)
bottomView.snp.makeConstraints {
    $0.left.bottom.right.equalTo(0)
}

let bottomView = BottomBar()
view.addSubview(bottomView)
bottomView.snp.makeConstraints {
    $0.left.right.equalTo(0)
    $0.bottom.equalTo(self.bottomView.snp.top).offset(-1)
}
用例三

明顯,我們看到上面那個工具條的底部沒有加上 safeAreaInsets.bottom ,但是右邊加上了 safeAreaInsets.right 。

到這里,我們可以得出總結(jié):

當視圖的任意邊跟屏幕的邊緣相交時,使用 layoutMarginsGuide 布局,系統(tǒng)會給相應的邊的邊距加上安全區(qū)域的邊距。

另外,我們可以在后續(xù)的使用中來動態(tài)調(diào)整 layoutMargins 的值,調(diào)整后,視圖會實時刷新相應邊距,甚至你可以給這個變化加上動畫。

是不是很Nice???

總結(jié)

這種布局方式,還是非常推薦使用的,通過上面的例子,我們就可以體會到它的妙處。在這個過程中,我們不需要考慮 safeAreaInsets ,僅僅只需要理解 layoutMarginslayoutMarginsGuide,并正確的使用即可。

本文只是簡單介紹了 layoutMarginslayoutMarginsGuide 的一部分使用,算是拋磚引玉。關(guān)于它的使用,我想只有你真正使用起來,你才會覺得這樣的設計的好處。

值得注意的是,在 iOS 11 推出了 directionalLayoutMargins ,也就是 layoutMargins 的替代物,使用起來并沒有大的差別,僅僅是換了個枚舉而已,感興趣的可以自己去試下。關(guān)于布局還有很多內(nèi)容值得研究,正確的使用系統(tǒng)提供的方法,可以使我們寫出更健壯的代碼,同時可以讓我們很好的適配不同的屏幕,和不同的設備。


如果這篇文章對你有幫助,不妨隨手點個贊!謝謝??

??原創(chuàng),禁止未授權(quán)轉(zhuǎn)載,只接收鏈接轉(zhuǎn)載,不接受內(nèi)容拷貝轉(zhuǎn)載!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • UIView可以說是我們?nèi)粘9ぷ髦薪佑|最多的一個對象、是所有視圖控件(不包括視圖控制器)的基類。主要的功能包括視圖...
    kirito_song閱讀 4,179評論 1 33
  • 序言 一個人有多不正經(jīng),就有多深情。一個程序員有多悶,就代表ta有多騷。我不等山無棱,不等夏雨雪,不等天地合。因為...
    _小迷糊_997閱讀 1,725評論 2 45
  • iOS 11正式發(fā)布了,下面整理了一些該版本下的特點還有如何進行兼容適配工作。 1. UIView變化 1.1. ...
    杰嗒嗒的阿杰閱讀 11,548評論 14 46
  • 關(guān)于iPhone X 的適配 為了實現(xiàn)更為安全的面部識別,iPhone X正面的全面屏上方有一條劉海,上面集成了紅...
    西貝人立口閱讀 3,202評論 0 4
  • 原文出自我在團隊技術(shù)公眾號發(fā)表的 《隨手記在iPhone X上的真機適配實踐總結(jié)》 Intro 前幾天,隨手記提交...
    JOJOTOV閱讀 2,450評論 1 15

友情鏈接更多精彩內(nèi)容