Xcode
iOS
UIScrollView
AutoLayout

UIScrollViewにおけるAutoLayoutについてまとめる

はじめに

StoryboardでのUIScrollViewの設定を、AutoLayoutだけでやろうとすると、かなり混乱します。
色々やっているうちに理解出来てきたのでまとめます。

UIScrollViewのパラメータについて

UIScrollViewには、表示するContentを管理するパラメータとして、

  • contentOffset
  • contentInset
  • contentSize

の3つがあります。
contentOffsetは、どれぐらいスクロールしているか。
contentInsetは、余分にどれだけスクロールできるか。
contentSizeは、スクロールする中身のサイズ。
をそれぞれ表しています。

AutoLayoutによって、中身に応じたcontentSizeを自動的に決定することが出来ます。

仕組み

この記事では、UIScrollViewの中にある、contentSizeの大きさを持ったスクロールするViewのことを、contentViewと呼ぶことにします。

混乱の元なのが、
「UIScrollViewの中に置いたViewの制約は、UIScrollViewからではなく、contentViewからの制約になり、それを元にcontentSizeが決定される」
ということです。

きったない絵で申し訳ないですが、以下をご覧ください。

d.png

このような制約をつけた場合、contentSizeは、600x500になる、ということです。
つまり、見かけ上UIScrollViewに対してつけている制約は、contentViewに対してつけていることになっています。

見た目に惑わされず、制約はUIScrollViewと同じサイズのViewに対してつけているのではなく、contentViewに対してつけている、ということを意識すると混乱しなくなると思います。

実践

とはいえ、このような仕組みを理解したとしても、常にcontentSizeを意識して制約をつけていくことはとても難しいです。
なので個人的には、UIScrollView直下にはUIViewを1つだけ配置して上下左右に0ptの制約をつける、という方法をオススメします。
そうすれば、あとはそのUIViewの高さと幅を決定すれば良い、という状態にすることが出来ます。

Xcodeではこんな感じ

スクリーンショット 2017-07-26 9.51.15.png

この状態から、UIViewに対して幅や高さの制約を追加したりサブビューを追加したりすると理解が深まると思います。

また、例えば横にのみスクロールしたい場合は、UIViewとUIScrollViewの間にEquals Heightsの制約をつければ良いです。

ちなみに

contentOffsetやcontentInsetはAutoLayoutではどうにもなりません。
contentInsetはUser Defined Runtime Attributesで指定できます。
こんなのもありましたが、僕のXcodeにはありませんでした。
contentOffsetは、AutoLayout適用後のviewDidLayoutで設定すると良いと思います。

参考

リファレンス
Qiita記事