今更なネタですが。
アプリのコンテンツ量が多くなってくると、いろんなコンテンツが混在した画面というものが登場します。最たる例はトップ画面です。
こんな雰囲気。
単純な場合はどのように組んでも問題は生じないのですが、次の場合頭を抱えることになります。
- 横スクロールが伴う
- 一部のコンテンツが、状況によって出たり出なかったりする
- 出たり出なかったりするのがAPIのレスポンス依存(後から決まる)
- APIが別れている、複数ある
- 高さがコンテンツの量に応じて変わる
- 高さがアニメーションにより増減する
- タッチイベントが競合する
- Viewが重い
- 一番下だけ無限スクロールでページングする
- スイッチが有り、コンテンツが切り替わる
こういった画面に遭遇した時、UITableView、UICollectionView、UIStackViewのどれかを使うことを検討すると思います。
そのUIStackViewでどう組むかという話です。
対象
UIStackViewがある程度分かる人
UITableVIewとUICollectionViewではダメなのか?
ダメではないと思います。
しかしこれらはハマりポイントが多数存在しがちです。
- 高さの変更でハマる(特にアニメーション)
- 非同期でAPI取得後、表示・非表示を制御する時にハマる
- Cellの場合は表示直前に生成するため、Cell内のViewが多いとスクロールする際にカクつくことがある(例えばCellの中にUICollectionViewが含まれている場合など)
- Cell内にUICollectionViewがあったりすると、設計に悩むしライフサイクルでも悩む
それでせっかく作ってもあーだこーだ調整に時間が掛かってしまうというのが過去数件ありました。
UIStackViewがこの全てを解決するわけではありませんが、仕様によってはUIStackViewを使うことでスッキリ書けることがあります。
UIStackViewが向かないもの
同じようなViewが連続する場合はもちろんCellを使ったほうがよいでしょう。
また、コンテンツ量が非常に多い場合なども向きません(といってもこれは本当に多いケースです)
ヘビーな画面を作る際は、画面表示時に1回だけ重いか、Cell表示時に毎回重いかどちらかを選択することになると思います。
ContainerViewでどのように高さを変更するか問題
これが本題です。
UIStackViewの中にContainerViewを含める場合、高さの制御が問題になります。
なぜか内部のUIViewContollerで自身のViewの高さをAutoLayoutで指定してもUIStackViewの高さに反映されてくれないのです。
できればUITableViewAutomaticDimensionのように、内部側から高さを決めたいですよね。
それを実現するためには、内部のUIViewControllerでこうします。
override func loadView() {
super.loadView()
self.view.translatesAutoresizingMaskIntoConstraints = false
}
これで解決します(理由は察せると思うので割愛。何だそんなことかー、と思いました)
サンプル
こういう状態で、ContainerViewをUIStackViewに入れます。
画面A
UITextViewのScrollableはオフにしています
このように、内部の高さに応じてUIStackView側の高さも変わっています。
一番上のViewControllerの中身はこの状態です↓
空っぽ!
鬼門:UIScrollView
何度やってもハマるUIScrollViewのAutoLayout
参考にどうぞ
UIScrollView -> 画面view 上下左右
ContentView -> UIScrollView 上下左右+EqualWidth
StackView -> ContentView 上下左右
このままだとエラーが出るので
UIView -> StackView 高さ固定
高さ固定を使わないなら、Remove at build timeにチェック
※UIScrollViewのContentLayoutGuideをOffにしないとエラーになります
このViewを使わないなら、viewDidLoadあたりでStackViewの中身を空に
(ここらへんもっとスマートな方法無いんですかね?AutoLayoutのエラーを放置する手もありますが)
UIStackView in UIStackViewは可能か?
上のサンプルの画面Cで既に使っています
大丈夫です
高さアニメーションしたら、見た目が少し変
こちら
[iOS]UIStackViewのアニメーションが変!
Viewにするか、ViewControllerにするか迷う
別解
ライブラリーを使うてもあるかも知れません(学習コストが高そうで、まだ使ったことありません)
StackViewController
https://github.com/seedco/StackViewController
AloeStackView
https://github.com/airbnb/AloeStackView
積み残した話題
一番下のコンテンツが無限スクロール(ページング)の場合はどうする?🤔
CellとStackViewのコラボレーションは少しハマりどころがあるのでまた別の機会に
あと、パーツをViewControllerにするにはちょっとコスト高いという場合にどう定義するのがスッキリするか、少し悩んでます
(UIStoryboard内にCustomViewを定義して、IBOutletを繋げない問題。Cellなら可能なんですけどねえ)
追記
このトピック無いなと思って書いたんですが、ありました。
巨大なビューをStoryboardだけで表現する
ContainerView周りの話題は認識しておいたほうが良いですね。