UIKitのチュートリアルを参考にCompositionalLayoutでListレイアウトを作成する手順と考え方を整理しました。
公式のチュートリアルと突き合わせると、理解が捗る資料を目指して作成しました。
対象読者:
- 公式のチュートリアルを実践済み
- 全体的な構成を俯瞰して把握することに苦労している人。
チュートリアルの概要:
公式が提供している「UIKit essentials Creating a list view」を題材とします。
このチュートリアルでは、データの更新が行えるリストレイアウトを作成します。
登場人物:
CompositionalLayoutでListを構築する上で、必要な登場人物を整理しましょう。
レイアウト構成とデータを持つ場所が違うため、それぞれについて以下で解説します。
リストレイアウトを構成
- UICollectionViewController:コレクションビューと関連する機能を統合的に管理
- UICollectionViewCompositionalLayout:
- UICollectionLayoutListConfiguration:リストの1つのセルの外観と、コレクションビュー全体のレイアウト情報を保持
- CellRegistration:デフォルトのセルの外観とデータを管理。
- defaultContentConfiguration:デフォルトのセルの外観情報を保持。
リストのセルに表示するコンテンツデータ
- ReminderModel
リストのセルに表示するコンテンツデータの管理
- Snapshot(NSDiffableDataSourceSnapshot):リストに表示するデータとデータモデルの整合性を保つためのある時点のデータを提供。
- DataSource:コレクションビューのデータの更新に基づき、ユーザーインターフェイスの更新を担当。
- dequeueConfiguredReusableCell:CellRegistrationと照らし合わせ、必要に応じて新しいコンテンツデータを代入し、Viewを描画。
登場人物たちの振る舞いを概観する
このコードは、MVCと呼ばれる、公式が推奨とされている構成で書かれています。
ViewとModelは完全に分離されており、Controllerに仲介されます。
チュートリアルにて登場した登場人物たちを、MVCモデルに当てはめてみました。
手順:
- リストレイアウトを構成するリストの1つのセルの外観とコレクションビュー全体のレイアウトを決める。
- コレクションビュー全体のの構成要素としてリストレイアウトを設定する。
(デフォルトのセルレイアウトを確定させる) - デフォルトのセルのレイアウトに、表示するコンテンツ(タイトルなど)のデフォルトのデータを与える。
- セルをデータソースに接続。データソースの更新に応じてレイアウトを変更する。
リストレイアウトを構成するリストの1つのセルの外観とコレクションビュー全体のレイアウトを決める
登場人物
- UICollectionViewCompositionalLayout:
- UICollectionLayoutListConfiguration:リストの1つのセルの外観と、コレクションビュー全体のレイアウト情報を保持
以下コードが該当部分です。
private func listLayout() -> UICollectionViewCompositionalLayout {
var listConfiguration = UICollectionLayoutListConfiguration(appearance: .grouped)
listConfiguration.showsSeparators = false
listConfiguration.backgroundColor = .clear
return UICollectionViewCompositionalLayout.list(using: listConfiguration)
}
ここではUICollectionViewCompositionalLayoutを継承したUICollectionLayoutListConfigurationを用い、リストの1つのセルの外観と、コレクションビュー全体のレイアウトを設定しています。
コレクションビューの構成要素としてリストレイアウトを設定する
登場人物
- UICollectionViewController:コレクションビューと関連する機能を統合的に管理
UICollectionViewController内のセクションの位置や外観の情報として、先ほど作成したlistLayoutを渡します。これにより、セルのデフォルトの外観の構成情報(defaultContentConfiguration)と コレクションビュー全体のセルの配置や全体的なレイアウトが確定します。
collectionView.collectionViewLayout = listLayout
デフォルトのセルのレイアウトに、表示するコンテンツ(タイトルなど)のデフォルトのデータを与える。
登場人物
- CellRegistration:デフォルトのセルの外観とデータを管理。
- defaultContentConfiguration:デフォルトのセルの外観情報を保持。
- ReminderModel
CellRegistrationにデータを渡し、表示するセルのデフォルトの外観とデータの初期の状態を定義します。
let cellRegistration = UICollectionView.CellRegistration {
(cell: UICollectionViewListCell, indexPath: IndexPath, itemIdentifier: String) in
let reminder = Reminder.sampleData[indexPath.item]
var contentConfiguration = cell.defaultContentConfiguration()
contentConfiguration.text = reminder.title
cell.contentConfiguration = contentConfiguration
}
セルをデータソースに接続。データソースの更新に応じてレイアウトを変更する。
登場人物
- Snapshot(NSDiffableDataSourceSnapshot):リストに表示するデータとデータモデルの整合性を保つためのある時点のデータを提供。
- DataSource:コレクションビューのデータの更新に基づき、ユーザーインターフェイスの更新を担当。
- dequeueConfiguredReusableCell:CellRegistrationと照らし合わせ、必要に応じて新しいコンテンツデータを代入し、Viewを描画。
Snapshot(NSDiffableDataSourceSnapshot) を作成します。
var snapshot = Snapshot()
snapshot.appendSections([0])
snapshot.appendItems(Reminder.sampleData.map { $0.title })
dataSource.apply(snapshot)
NSDiffableDataSourceSnapshot
は、データソースに対して変更を適用するためのスナップショットを表現するクラスです。古いデータセットと新しいデータセットの差分を計算し、dataSource
に適用します。
dataSource.apply(snapshot)
にて dataSource
に snapshot
が反映されています。
レイアウトの更新を行いましょう。
dataSource = DataSource(collectionView: collectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, itemIdentifier: String) in
return collectionView.dequeueConfiguredReusableCell(
using: cellRegistration, for: indexPath, item: itemIdentifier)
}
dequeueConfiguredReusableCell
に、先ほど作成したconfiguration
を渡し、必要に応じて新しいコンテンツデータを代入し、Viewを描画を行います。
おすすめ情報
2020年のWWDCにて、「Lists in UICollectionView」と「Advances in Collection View Layout」という発表があります。合わせて参照すると理解が深まりそうです。