はじめに
こんにちは、iOSエンジニアの dayossi です。
家族が幸せになれるサービスを提供したいと思って、
HaloHaloという家族日記アプリをリリースしています。
今回は、いまさらながら
UICollectionViewの描画タイミングの全体像について
整理したいと思います。
( 詳しいコードなどは、ほかの方の記事がわかりやすいので
最後にご紹介しております )
CollectionViewのレイアウトをいじりたいけど…
CollectionViewのレイアウトを
もっといろいろカスタマイズしたいなーと思って
UICollectionViewLayoutで一からレイアウトを組んでみたら、
「どのタイミングでレイアウト更新したらいいんだっけ?」
「セルに載せたUILabelとかUIImageViewのデータ更新もしたいけど、
どのタイミングでセルの作成とか更新とかしてるんだ?」
と、途中からわからなくなってきたので整理しました。
UICollectionViewがCellを表示する大まかな流れ
大きな流れとしては
CollectionView全体のレイアウトを決めてから、セルを作る作業に入ること
が大事かなと思いました。
まず、最初にCollectionViewが作られるときは
以下の UICollectionViewDataSource
のメソッド(濃いグレー)が呼ばれます。
ここでは、
画面いっぱいに映る数 + 次に表示される 画面半分だけの数の
CollectionViewCell
( 以下 セル ) が作られます。
なお、以下のメソッドはオプションなので
書かなくてもいいものです。
・ CollectionViewCell.prepareForReuse()
・ DataSource.prefetch()
(iOS 10から追加)
この中で、レイアウトを指定するメソッドも呼ばれています。
呼ばれるタイミングは、
-
DataSource.numberOfItemsInSection
の前からです。
(薄いグレー :UICollectionViewLayout
のメソッドです)
( DataSource.willDisplay()
はオプションメソッドなので
記述しなくても動きます )
注:layoutAttributesForItem()
のタイミングは、
(初期設定時は厳密に)ハッキリとわかりませんでした。あくまで予測です。
以上から
CollectionView全体のレイアウトを決めてから、セルを作る作業に入る
という流れが見えると思います。
ここからCollectionViewを下へスクロールすると、
以下のようにメソッドが呼ばれます。
(DataSource.didEndDisplay()
はオプションメソッドなので
記述しなくても動きます )
基本的な流れは変わりませんが、上に消えていったセルは
初期設定時に準備された 緑色のセル の次に格納されるのがポイントです。
UICollectionViewLayoutを再度呼び出したいとき
先ほどの図のように
先に作ったセルを再利用して、スクロールした先のセルは表示されるので
特に書き換える処理がなければ
消えたセルの内容がそのまま次に出てくるセルに使用されます。
なので、表示したいものにあわせてレイアウトを変えたい場合は
もういちど計算しなおす必要がでてきます。
再利用するセルのレイアウトを変えたいときは、
collectionView.invalidLayout()
を呼ぶ必要があります。
DataSource.prepareForReuse()
の中で
collectionView.invalidLayout()
を呼ぶと、
次にセルを再利用する際に、レイアウトをスムーズに変更できると思います。
また、レイアウト・UILabelなどのプロパティUI表示も変更したい場合は
DataSource.prepareForReuse()
の中で、更新対象のプロパティにnilを代入したあと
任意のタイミングで
collectionView.reloadData()
collectionView.reloadSections( )
のようなリロード処理を呼び出すと、まるっと対応可能です。
ただ、collectionView.reloadData()
よりも
collectionView.reloadSections()
で
必要な部分だけ更新するやり方のほうが
メモリに優しい印象です。
終わりに
UICollectionViewのレイアウトは、iOS13から使用可能な
Compositional Layoutを使えば、
レイアウトのカスタマイズは結構カンタンにできます。
(私もコレに任せて、HaloHaloを作成しました)
基本的なところを改めて学び直してみると
OSバージョンの壁を超えて、より多くの方に
より使いやすいUIを考えられると思いました。
まだまだ未熟者なので、
「ここはこう考えたほうがいいよ!」など
温かいご指摘などを頂けますと幸いです。
最後までお読みいただき、ありがとうございます。
参考記事
ちょっと長いですが、はじめに見たほうが良かったです…!!
A Tour of UICollectionView (WWDC 2018)
What's New in UICollectionView in iOS 10 (WWDC 2016)
具体的に考えていく際に、とても参考になりました!!
[iOSDC 2016] iOS10のCollectionViewからライフサイクルが変わったので遊んでみた
【Swift】CollectionViewを再理解する
CollectionViewのカスタムレイアウトを作ってみた
UICollectionView の Layout で悩んだら
UICollectionViewのカスタムレイアウトの作り方