【iOS】📦コンテナViewの採用基準👨

# TL;DR
UIKitには4つのコンテナViewがありますが、どれを選択すべきなのか、
自分の中で曖昧だな〜と思ったので、整理しました。

# コンテナViewって？
UIViewに直接パーツを貼り付けても実装は可能ですが、
それをやると細かいUI調整がしんどくなります。
しかも動的にデータが更新されるようなアプリだったら、厳しいですね。
そこでコンテナViewというViewにパーツを乗せて、レイアウトやデータ更新を制御しやすくします。

# UIKitのコンテナView概観
詳細については後述しますが、UIKitの標準クラスとしては4つあります。

[UICollectionView](https://developer.apple.com/documentation/uikit/uicollectionview)
[UITableView](https://developer.apple.com/documentation/uikit/uitableview)
[UIStackView](https://developer.apple.com/documentation/uikit/uistackview)
[UIScrollView](https://developer.apple.com/documentation/uikit/uiscrollview)

なんか特徴のない名前なので、並べてみると違いがわかりづらいですね。
Interface Builder使うと、[「Container View」](https://qiita.com/ponnjinnka/items/a9bf82b2767a67f12335)ってやつが選択できて、
これ抜けてるんじゃない？　と思うかもしれませんが、実体はUIViewです。

# メリット/デメリット比較
結論から書くスタイルで行こうと思います。
４つのメリ/デメを比較しました。

| Class Name         | スクロール可能 | 水平方向に配置可能 | Auto Layoutとの相性|
|:------------------:|:-----------:|:--------------:|:-----------------:|
| UITableView        | ◯           | ×              |△                  |
| UICollectionView   | ◯           | ◯              |△                  |
| UIStackView        | ×           | ◯              |◯                  |
| UIScrollView       | ◯           | ◯              |×                  |

- UITableView/UICollectionViewはUIScrollViewを継承しており、基本的には上位互換
- 僕自身は実務でAuto Layout使った経験がないので、相性は雰囲気
- ４つのクラスそれぞれ長所・短所があるので、どれを使うのがよいかは要件次第
    - ただUIScrollViewを使うケースはあんまないのかなあという気も
    - パーツが少なくて、スクロールしたいだけの単純なページをつくる際に、サブクラスだとDelegateメソッドがごちゃごちゃしていてめんどくさいときとか？
- UIStackViewだけで完結する要件もあまりない気がするので、何かしら組み合わせになる気はする
 
あとなんかあった方がいい評価軸あったらご指摘ください

# UITableView
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333454/074d5c17-6057-4308-4f6a-0cb5a280b083.png)
iPhoneといえばこのUIですよね。
テーブル形式で表現できるデータに対して使うViewです。
UIはシンプルなんですが、UITableViewDelegate/UITableViewDataSourceという２つのprotocolに従っており、
Delegate経由でセルの個数やらデータ内容やらを返してやるので、初見だと戸惑いました。
protocolもなんで２つに分かれてんねん、と思っていましたが、
よく考えたらViewに関するprotocolとModelに関するものを分けてるんですね。
データがちゃんと階層型になっていて、それを無骨に表示すればOKであれば、UITableViewを使うべきでしょう。

セルの再利用の概念がちょっとハマりどころかなと思います。
横スクロールには対応していないのが制約です。

# UICollectionView
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333454/c4be19db-50f6-718c-8bc7-d8b6270f8fb2.png)
UICollectionViewは「コレクション」という名前のとおり、ユーザーにデータを見せる、という意味合いがより強いUIです。
UITableViewと何が違うの、というのを深く考えていくと、実はかなり似ていて、思ったより違いを説明するのが難しいことに気づきました。
(delegateの設計もそっくりですし)
ただ、

- より複雑なレイアウトをつくりたい
- 横向きにスクロールさせたい

という要件であれば、UITableViewよりUICollectionViewです。

# UIStackView
| Horizontal | Vertical |
|:---:|:---:|
|<img width="505" alt="axis-horizontal.png" src="https://qiita-image-store.s3.amazonaws.com/0/31069/879b22d0-2b61-08d3-23c5-f3e1cce7b0ab.png">|<img width="505" alt="axis-vertical.png" src="https://qiita-image-store.s3.amazonaws.com/0/31069/115a359a-d8d6-b1ee-8664-3c79c71a4a26.png">|

UIStackViewは前述のUITableView/UICollectionViewとは全く違うコンテナViewです。
なのでちょっと頭を切り替えてください。
モノとしては、要素をスタック（積む）していくだけのコンテナです。
垂直方向、水平方向が選べます。

たぶん歴史的なところから説明するのが一番わかりやすいと思うので歴史を話します。
UIStackViewは、iOS 9.0から登場した、比較的新しいクラスです。
そもそもAuto Layoutという概念がiOS 6.0で導入されました。
端末で言うとiPhone5の頃ですね。
iPhone4s以前では、iPhoneの画面は3.5インチだったので、アプリもそのサイズだけを考えていればよかったんですが、
iPhone5から4インチに画面が広がり、その後デバイスは更に多様化していきました。

UITableView/UICollectionViewのレイアウトに関する課題として、下記がありました。

- 制約が複雑化・肥大化してメンテナンスしきれない
- 画面の回転時にパーツの更新がカクつく（動的変更に弱い）

Auto Layoutを意識したコンテナViewということで、UIStackViewが登場しました。

[遅ればせながら UIStackView 入門](https://qiita.com/tasanobu/items/6908c956b758547ccf6c)

シンプルな構造で、制約がつけやすいというメリットとともに、
要素にisHiddenという属性があるので、UITableView/UICollectionViewではセルのRemove/Reload操作が必要だったところを、
単にユーザーに見せたくないタイミングで隠して、表示したいときに表示、ということができるので、動的変更に強くなりました。

使いやすい設計になっていますが、スクロールができないという弱点があります。
（４つのコンテナViewの中で、これだけUIScrollViewを継承していません）
実務的には、UIStackViewの上にUIScrollView系のViewを乗せてスクロールさせることになるんじゃないでしょうか。

# UIScrollView
スクロールさせられるViewです。

# まとめ
というわけで、コンテナViewの採用基準としては、下記の流れで考えればよいでしょうか。

- そもそもコンテナViewにするほど要素が多いのか？
    - ならないならUIViewに直乗せでも可
    - 多いor将来の拡張性持たせたいなら次へ
- UITableView/UICollectionViewを採用できないか？
    - どちらかを選べるなら次へ
- 複雑な画面制約をつけることになりそうか？
    - そこまでAutoLayoutがゴチャつかないなら、UITableView/UICollectionViewを採用
    - ゴチャつくのが予想されるなら、UIStackViewを採用
        - スクロールが不要なら、それで終わり
        - スクロールが必要なら、UITableView/UICollectionView/UIScrollViewと組み合わせる

何か抜けてる観点あれば、ご指摘or修正リクエストお願いします〜🙏

# おまけ
[UIKit Catalog: Creating and Customizing Views and Controls](https://developer.apple.com/documentation/uikit/mac_catalyst/uikit_catalog_creating_and_customizing_views_and_controls)

この記事書くためにAppleのドキュメント漁っていたら、UIKitの標準Viewのサンプルコードを公開してくれてるのを発見しました。