ScrollViewとStackViewを使った簡単でレイアウト変更に強い実装方法

##はじめに
Storyboard上でのScrollViewの実装って結構ややこしいですよね。。。


Autolayoutの設定がわからないとかAutolayoutは設定できたけどスクロールがうまくいかないとか...
初心者の方は特に躓くのではないかと思います。

そんなややこしいScrollViewの実装を簡単にできる方法を紹介したいと思います。


みなさん、ScrollViewをStoryboardで実装するときどのように実装していますか？
ScrollViewのContentViewに**UIView**を置いていませんか？

ScrollViewの実装の仕方を調べると大抵の記事はcontentViewにUIViewを置いているのではないかと思います。
UIViewを置くことは間違いではないのですが、このUIViewをStackViewに置き換えることで簡単に実装することができレイアウトの変更に強くなります。


##ScrollViewのcontentViewにStackViewを配置する


まずはScrollViewを配置してAutolayoutを設定します。
今回は上下左右0ptで指定します。
![スクリーンショット 2019-03-01 18.48.42.png](https://qiita-image-store.s3.amazonaws.com/0/106260/b4fa5690-7b85-d080-5abd-714a075cc309.png)

次にStackViewをScrollViewのcontentViewに配置します。
今回は縦方向のスクロールにするのでStackViewは**Vertical**のもを使います。
また、StackViewのDistributionを***Equal Spacing***にしましょう。※ここお忘れなく！

AutolayoutはScrollViewのときと同じように上下左右0ptで設定します。

これだけだとエラーが出るので加えてStackViewの横幅をScrollViewと同じにします。
![スクリーンショット_2019-03-01_18_56_36.png](https://qiita-image-store.s3.amazonaws.com/0/106260/bd8581f0-c9b0-62f6-46fb-dd3799ae0838.png)

ScrollViewのところまで引っ張って離すとWindowが出てくるので**Equal Widths**を選択します。
これでStackViewの横幅がScrollViewと同じになりました。

ここまではUIViewでの実装と同じです。

##UIViewでの実装との違い

ここまでのAutolayoutの設定でまだエラーが出てますね。
では配置したStackViewの中にUIViewを配置してみましょう。


ここでUIViewでの実装との違いを解説します。

contentViewがUIViewの場合、ここまでの手順でエラーは消えません。
contentViewの高さが確定していないためです。
UIViewの場合、中に配置するUIパーツ全ての高さが確定し、全体の高さが決まっていないといけません。

ですが、StackViewを使うと高さのAutolayoutを指定しなくてもエラーにならないのです。
全体のcontent sizeはStackViewが中のUIパーツの高さをみて勝手に計算してくれます。

後は配置したUIViewの中で配置した各UIパーツにAutolayoutを指定していきましょう。
UIView自体に高さを指定しても大丈夫です。

では実際に実行して見てみましょう。

まずは中のUIViewの高さを100にして見てみます。

![スクリーンショット 2019-03-01 19.58.10.png](https://qiita-image-store.s3.amazonaws.com/0/106260/48b051f2-deed-3046-80e0-ad8de4d4a21b.png)


この場合ScrollViewのcontent sizeが100になり、画面内に収まるのでスクロールできません。



次に高さを2000にして見てみましょう。
Storyboard上からはみ出ていますが、一旦気にしなくて大丈夫です。
気になる方はStoryboardのサイズを変えてください！

![スクリーンショット 2019-03-01 20.04.08.png](https://qiita-image-store.s3.amazonaws.com/0/106260/220ed0d3-f82d-4eb0-3f78-0b7ac3810801.png)


少しわかりづらいかもしれませんが、スクロールができていると思います。

このようにcontent sizeはStackViewが勝手に計算してくれます。


##StackViewを使うメリット
ScrollViewのcontent viewにStackViewを使うと以下のメリットがあります。

・全てのレイアウトが完成しなくてもエラーにならない
・content view(StackView)自体の高さのAutolayoutを設定しなくてよい
・レイアウトの修正をするときにAutolayoutの再設定が楽になる ※これが一番うれしいかも


##中に配置するViewを切り出してxibで作る

先程配置したUIViewの中で全てのUIパーツを組み立てても良いのですが、デザインや実装の都合上区切りのよいところで分けてそれぞれをxibで作りましょう。
※分けたxibはそれぞれxib内でAutolayoutを設定してください。Storyboard上でデザインを確認したい方はxibのクラスに[@IBDesignable](https://qiita.com/son_s/items/7ca2acf690d10f9fd1b7)を設定しましょう。

xibのレイアウトが完成したらStackViewの中にUIViewを置いてUIViewクラスにxibで作ったクラスを指定します。
このとき配置したUIViewにはAutolayoutを指定しなくて大丈夫です。

ここまでできたら実行してみてください。

どうでしょう？
Storyboard上ではAutolayoutを設定していませんが、ちゃんとxib側で設定したAutolayoutの通りの高さになっているのではないでしょうか？

全てをStoryboard上で組み立てるとレイアウトの修正をするときAutolayoutの修正がとても大変です。
ですが、このようにxibに切り出して実装するとレイアウトの修正する際、切り出したxib内のAutolayoutを修正するだけでよくなります。

以上、StackViewを使ったScrollViewの実装方法でした。

##※追記
Xcode11からScrollViewの変更が入ったようで、ScrollViewの中に `Content Layout Guide` と `Frame Layout Guide` というものが含まれるようになっています。
<img width="1362" alt="スクリーンショット_2019-10-08_11_49_06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106260/8374bfa5-585c-321d-b19f-65b41ab4404e.png">

この変更により、この記事のやり方でエラーが出るようになったので、ScrollViewを配置後、ScrollViewを選択して `Content Layout Guides` のチェックを外してから中にStackViewを配置してください。
<img width="1368" alt="スクリーンショット_2019-10-08_11_55_43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106260/5475525e-be3b-061d-ccbd-805f22a6a91f.png">