tomoyaonishiのブログ

iOSのことを中心に・・・その他もあるよ!

UILayoutGuideを使って意味のないUIViewを使わないようにする

UILayoutGuideとはAutoLayoutのための矩形領域表現クラスです。簡単に言うとUIViewからレンダリングとタッチイベント機能を取り去ったものです。

iOS11でSafeAreaが登場したのでview.safeAreaLayoutGuideが有名でしょうか、これがUILayoutGuideです。

実はiOS9から登場していて、view.layoutMarginsGuide, view.readableContentGuideもUILayoutGuideです。

で本題です。

UILayoutGuideはシステムが作るものと思う人がいるかも知れませんが、自分でも作成できます。

何ができるかというと、冒頭で記述したようにAutoLayoutのための矩形領域をUIViewなしで表現できます。たとえば、2つのViewをまとめて空のUIViewに乗せて、空のUIViewをセンタリングするみたいなことはよくあると思います。また、3つのViewを均等に表示するために空のUIViewをスペーサーとして使うこともあるでしょう。

UILayoutGuideを使えば空のViewは不要になります。

たとえば、均等に表示する場合、今までだと

[view1] - [dummyView1] - [view2] - [dummyView2] - [view3]

として、dummyView1,2の横幅を制御して均等に表示していました。

これをUILayoutGuideを使うと

[view1] - [UILayoutGuide] - [view2] - [UILayoutGuide] - [view3]

となります。

        let space1 = UILayoutGuide()
        view.addLayoutGuide(space1)
        
        let space2 = UILayoutGuide()
        view.addLayoutGuide(space2)
        
        space1.widthAnchor.constraint(equalTo: space2.widthAnchor).isActive = true
        space2.widthAnchor.constraint(equalToConstant: 50).isActive = true
        
        label2.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label2.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        
        label1.centerYAnchor.constraint(equalTo: label2.centerYAnchor).isActive = true
        label1.rightAnchor.constraint(equalTo: space1.leftAnchor).isActive = true
        space1.rightAnchor.constraint(equalTo: label2.leftAnchor).isActive = true
        label2.rightAnchor.constraint(equalTo: space2.leftAnchor).isActive = true
        space2.rightAnchor.constraint(equalTo: label3.leftAnchor).isActive = true
        label3.centerYAnchor.constraint(equalTo: label2.centerYAnchor).isActive = true

こんな感じです。

メリットとしてUILayoutGuideはUIViewではないので、View階層を汚しません。空のUIViewを使いだすとUIの構造が分かりづらくなったりするのでなるべくこちらのほうがいいと思います。

とはいえ、StackViewでええやんっていうところもあるし、使い所次第ですね。

UILayoutGuideが生まれた背景は、AutoLayoutのために空のUIViewを使うことは、

  1. 自身の生成コストと運用コスト
  2. View階層に追加されるので、View階層に対するタスク時のオーバーヘッド
  3. 空の透明なViewは本来の意味で使われる他のViewへのメッセージングを阻害してしまう。(タッチイベントを意図せず奪ってしまうとか?)このような不具合のデバッグは非常に難しい。

の3つが挙げられていました。

UILayoutGuide - UIKit | Apple Developer Documentation

サンプルコードはこちらです。

github.com