post Image
safeAreaLayoutGuideをiOS 10で使う(?)

もちろんできません

safeAreaLayoutGuideはiOS 11+のみで使えるので、iOS 10等をサポートしているとエラーになります。

大抵の場合は、画面端からの代わりにsafeAreaを使って、iPhone Xでもレイアウト崩れないようにしたいと思います。

とはいえ、レイアウトごとに

if #available(iOS 11.0, *) {
    view.safeAreaLayoutGuide.leftAnchor
} else {
    view.leftAnchor
}

みたいにするのは冗長です。

これを同じように扱えればよいわけです。

第一案

結果

UIViewのAnchorを、UILayoutGuideとして取り出すことで対応しました。

let safeAreaLayoutGuide = view.safeLayoutGuideOrSelfLayoutGuide()

これでiOS 11以上ならsafeAreaLayoutGuideが、iOS 10以下では自分自身のLayoutGuideが返されます。

実装

まず、leftAnchorなどはUIViewのプロパティなので、ProxyするクラスをUILayoutGuideを継承して作ります

private final class UIViewLayoutGuideProxy: UILayoutGuide {

    private unowned var _base: UIView

    override var leftAnchor: NSLayoutXAxisAnchor {
        return _base.leftAnchor
    }

}

そして、このiOS 10以下ではこのProxyを返すようなメソッドを生やせば完了です。

extension UIView {
    func safeLayoutGuideOrSelfLayoutGuide() -> UILayoutGuide {
        if #available(iOS 11.0, *) {
            return self.safeAreaLayoutGuide
        } else {
            return UIViewLayoutGuideProxy(self)
        }
    }
}

Gist

以下でソースを公開しています(案1の方)

https://gist.github.com/ha1f/884ce4870dc395639e86c4395f5ea947

第二案

extension UIView {
    var safeLeftAnchor: NSLayoutXAxisAnchor {
        if #available(iOS 11.0, *) {
            return self.safeAreaLayoutGuide
        } else {
            return self.leftAnchor
        }
    }
}

みたいなのも考えましたが、せっかく .leftAnchor の名前はUIViewでもUILayoutGuideでも揃っているので、崩したくないなと思いました。
が、以下のようにviewがdeinitされた後に呼ばれる可能性がなくなるので、こっちのほうがいいかもしれません、、、(今更)

let tmp = view.safeLayoutGuideOrSelfLayoutGuide()
// viewがdeinitされた後に呼ぶと_baseがnilで落ちる
print(tmp.leftAnchor)

案2として同じGistの下側にあります!

第三案

Rxみたいにしてみた。これが一番いいかも

https://gist.github.com/ha1f/457b8427da3e37d5c72dcc61465b9f17

view.safeAreaLayoutGuideCompatible.leftAnchor

という感じ


『 Swift 』Article List