LoginSignup
2
3

More than 3 years have passed since last update.

UICollectionViewLayoutを使ったときのUICollectionViewの描画サイクル

Posted at

はじめに

こんにちは、iOSエンジニアの dayossi です。

家族が幸せになれるサービスを提供したいと思って、
HaloHaloという家族日記アプリをリリースしています。

今回は、いまさらながら
UICollectionViewの描画タイミングの全体像について
整理したいと思います。
( 詳しいコードなどは、ほかの方の記事がわかりやすいので
最後にご紹介しております )

CollectionViewのレイアウトをいじりたいけど…

CollectionViewのレイアウトを
もっといろいろカスタマイズしたいなーと思って
UICollectionViewLayoutで一からレイアウトを組んでみたら、

「どのタイミングでレイアウト更新したらいいんだっけ?」
「セルに載せたUILabelとかUIImageViewのデータ更新もしたいけど、
どのタイミングでセルの作成とか更新とかしてるんだ?」

と、途中からわからなくなってきたので整理しました。

UICollectionViewがCellを表示する大まかな流れ

大きな流れとしては
CollectionView全体のレイアウトを決めてから、セルを作る作業に入ること
が大事かなと思いました。

まず、最初にCollectionViewが作られるときは
以下の UICollectionViewDataSource のメソッド(濃いグレー)が呼ばれます。

ここでは、
画面いっぱいに映る数 + 次に表示される 画面半分だけの数の
CollectionViewCell( 以下 セル ) が作られます。

スクリーンショット 2020-09-23 20.18.17.png

なお、以下のメソッドはオプションなので
書かなくてもいいものです。
CollectionViewCell.prepareForReuse()
DataSource.prefetch() (iOS 10から追加)

この中で、レイアウトを指定するメソッドも呼ばれています。

呼ばれるタイミングは、
1. DataSource.numberOfItemsInSection の前からです。
(薄いグレー : UICollectionViewLayout のメソッドです)

スクリーンショット 2020-09-23 20.16.21.png

( DataSource.willDisplay() はオプションメソッドなので
記述しなくても動きます )

注:layoutAttributesForItem()のタイミングは、
  (初期設定時は厳密に)ハッキリとわかりませんでした。あくまで予測です。

以上から
CollectionView全体のレイアウトを決めてから、セルを作る作業に入る
という流れが見えると思います。


ここからCollectionViewを下へスクロールすると、
以下のようにメソッドが呼ばれます。
スクリーンショット 2020-09-23 20.46.29.png

DataSource.didEndDisplay() はオプションメソッドなので
記述しなくても動きます )

基本的な流れは変わりませんが、上に消えていったセルは
初期設定時に準備された 緑色のセル の次に格納されるのがポイントです。

UICollectionViewLayoutを再度呼び出したいとき

先ほどの図のように
先に作ったセルを再利用して、スクロールした先のセルは表示されるので

特に書き換える処理がなければ
消えたセルの内容がそのまま次に出てくるセルに使用されます。

スクリーンショット 2020-09-23 20.46.29.png

なので、表示したいものにあわせてレイアウトを変えたい場合は
もういちど計算しなおす必要がでてきます。

再利用するセルのレイアウトを変えたいときは、
collectionView.invalidLayout()を呼ぶ必要があります。

スクリーンショット 2020-09-23 20.46.42.png

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のカスタムレイアウトの作り方

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3