Edited at

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

More than 1 year has passed since last update.


はじめに

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記事