pixiv insideは移転しました! ≫ https://inside.pixiv.blog/

入社半年で学んだAutoLayoutと仲良くなる方法をまとめてみる

こんにちは。ピクシブ株式会社 Advent Calendar 2015の7日目の記事を担当します新卒iOSエンジニアの@yuutetuです。

私は入社以前はRuby on Railsでのサーバサイドの開発をしていて、入社した今年の4月からiOS開発をしています。始めの頃はiOSアプリのレイアウト構築のために広く使われるAutoLayoutに苦戦していました。今回は、AutoLayoutについて入社してから半年間で学んだことをまとめます。

最も大事なこと

AutoLayoutでレイアウトを組む上でもっとも重要なことは 位置と大きさが確定するように組むこと です。当たり前のことだと思うかもしれませんが、UILabelなどの 自分自身で大きさを決められるView もあるためわかりにくくなることもあります。このことを意識するだけでAutoLayoutを理解しやすくなります!

基本的な使い方

f:id:yuutetu:20151207210351p:plain

AutoLayoutでは以下の様な内容を設定できます。

  • Super Viewとの間のマージン
  • 隣接するViewとの間隔
  • Viewの大きさ
  • 端を他のViewと揃える
  • 大きさを他のViewと揃える
  • などなど・・・

これらを組み合わせてレイアウトを設定していきます。幾つかレイアウトの例を挙げてみましょう。

f:id:yuutetu:20151207115452p:plain

特殊なViewの扱い方

ここまでであればまだ単純なのですが、いくつか特別な扱いが必要なViewがあります。

自分自身で大きさを決められるView(UILabelやUIImageViewなど)

f:id:yuutetu:20151207115543p:plain

UILabelやUIImageViewなど、AutoLayoutで大きさを指定しなくてもエラーにならないViewがあります。これらのViewは 自分自身で大きさを決められるView であるためです。それぞれ以下のような横幅・縦幅になります。

  • UILabel:表示する文字列が収まる横幅・縦幅
  • UIImageView:表示する画像が収まる横幅・縦幅

ただし、これらの優先度は低く、横幅・縦幅を定めるAutoLayoutを設定すれば設定したものが優先されます。 UILabelの表示領域の大きさが文字列の長さに応じて変化して欲しい場合には、"幅の最大が200px"など緩めに設定しましょう。

外枠と内部の大きさが独立しているView(UIScollViewなど)

AutoLayoutを使用するにおいて、UIScrollView上での設定で苦労したiOSエンジニアは多いです。UIScrollViewは 外部の位置・大きさに加えて内部の大きさを指定する必要がある数少ないViewの一つです。よくあるミスは以下のようにAutoLayoutを設定した時に発生します。

f:id:yuutetu:20151207115637p:plain

この設定で良さそうに見えますが、配置したUIViewの大きさが確定できずエラーになります。UIScrollViewの内側を点線で可視化してみると以下のようになります。

f:id:yuutetu:20151207115723p:plain

内側の大きさはUIScrollViewに外部からAutoLayoutで設定しても決めることはできません。内側のUIViewの大きさを以下のように決めてあげるとうまく動きます。

f:id:yuutetu:20151207115806p:plain

特殊なViewを作ってみよう

上記でいくつか特殊なViewを紹介しましたが、このようなViewは自作することもできます。UILabelのように横幅・縦幅を自分自身で決めることができるViewの作り方を紹介します。作り方は以下の2通りがあります。

  • UILabel等のViewをAutoLayoutを用いてレイアウトする
  • UIView#intrinsicContentSizeを実装する

下の方法を使うには、以下のように関数をオーバーライドするといいです。

override func sizeThatFit() -> CGSize {
    let size = ... // 中に表示するものがぴったり収まる大きさを返す
    return size
}

override func intrinsicContentSize() -> CGSize {
    return self.sizeThatFit()
}

UIView#sizeThatFit は内部に表示するコンテンツがぴったり収まる大きさを返すメソッドで、内部に表示するコンテンツがぴったり収まるように大きさを変える UIView#sizeToFit で使用されています。 UIView#intrinsicContentSize は、AutoLayoutでレイアウトされる際にViewの理想の大きさを返すメソッドです。このメソッドをオーバーライドすることによってUILabelのような動的にサイズを変更することができるViewを実装することができます。

まとめ

AutoLayoutでできることを知ると今まで view.frame = ... と手動で座標を指定していた箇所もAutoLayoutで楽に設定することができます!AutoLayoutと仲良くなるiOSエンジニアが1人でも増えれば幸いです。

次回は同じく新卒の@ik-fibです。お楽しみに!