ハイライト
iOS 14 では UICollectionView が
UICollectionLayoutListConfigurationで UITableView 風リストを作れ、UICollectionViewListCellで自适应高さ、区切り線、スワイプ操作、accessories を設定できます。
主要内容
多くの UIKit プロジェクトには厄介な境界があります。単純なリストは UITableView、複雑なレイアウトは UICollectionView。ページにリスト、横スクロール領域、グリッド、階層構造が同時に必要になると、開発者は2体系を行き来し、データソースとレイアウトコードが分断されます。
iOS 14 はリストを UICollectionView に入れました。UICollectionLayoutListConfiguration は plain、grouped、inset-grouped、iPad sidebar 向けの sidebar、sidebar plain 外観を提供します。Compositional Layout 上に構築されるため、同じ collection view に表風リスト、直交スクロール領域、カスタムグリッドを共存させられます。
リスト cell も再設計されました。UICollectionViewListCell はデフォルトの自适应高さ、区切り線 layout guide、leading/trailing swipe actions、宣言的 accessories をサポートします。講演では特に警告しています。swipe action は index path を捕まえないでください。上に挿入や削除があると、古い index path は別データを指す可能性があります。
これにより UICollectionView がリスト画面のデフォルト起点になります。まず元の table view 外観を置き換え、その後 section ごとに横領域、outline、iPad sidebar を足せます。
詳細
collection view 全体のリストレイアウトを作る
(03:47) 最も単純な入口は UICollectionLayoutListConfiguration を作り、UICollectionViewCompositionalLayout.list(using:) に渡すことです。全 section が同じリスト外観のページに適します。
// Simple setup
let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let layout = UICollectionViewCompositionalLayout.list(using: configuration)
キーポイント:
UICollectionLayoutListConfigurationはレイアウト側でリストを作る新しい型です。appearance: .insetGroupedは inset grouped table view 風の外観を生成します。UICollectionViewCompositionalLayout.list(using:)は collection view 全体のレイアウトを直接生成します。
section ごとにリストとカスタムレイアウトを混在させる
(04:40) 一部の section だけがリストなら、Compositional Layout の section provider を使います。システムが section レイアウトを要求するたびに、リスト section かカスタム section を返せます。
// Per section setup
let layout = UICollectionViewCompositionalLayout() {
[weak self] sectionIndex, layoutEnvironment in
guard let self = self else { return nil }
// @todo: add custom layout sections for various sections
let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let section = NSCollectionLayoutSection.list(using: configuration, layoutEnvironment: layoutEnvironment)
return section
}
キーポイント:
- section provider は
sectionIndexとlayoutEnvironmentを受け取り、section ごとに異なるレイアウトを返せます。 NSCollectionLayoutSection.list(using:layoutEnvironment:)は現在の section のリストレイアウトだけを作ります。- カスタムグリッド、横スクロール領域、リストは同じ
UICollectionViewCompositionalLayoutに共存できます。
header と footer を明示的に有効にする
(05:49) リストの header と footer は明示的に有効化が必要です。headerMode または footerMode を .supplementary にすると、collection view は data source か delegate に supplementary view を要求します。
var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
configuration.headerMode = .supplementary
let layout = UICollectionViewCompositionalLayout.list(using: configuration)
dataSource.supplementaryViewProvider = { (collectionView, elementKind, indexPath) in
if elementKind == UICollectionView.elementKindSectionHeader {
return collectionView.dequeueConfiguredReusableSupplementary(using: header, for: indexPath)
}
else {
return nil
}
}
キーポイント:
.supplementaryは header が supplementary view で提供されることを意味します。supplementaryViewProviderはUICollectionView.elementKindSectionHeaderや footer の element kind を判定する必要があります。- transcript は明確に警告します。supplementary モード有効後、header/footer 要求時に
nilを返すと assertion が発生します。
(07:07) 階層データには firstItemInSection がより適します。section の最初の item を header 外観に設定し、section snapshot と相性が良いです。
var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
configuration.headerMode = .firstItemInSection
let layout = UICollectionViewCompositionalLayout.list(using: configuration)
キーポイント:
firstItemInSectionは header にのみ適用されます。- このモードでは data source の最初の item が header を表し、通常コンテンツではありません。
- 講演は階層データ構造と新しい section snapshot API に使うことを勧めます。
cell に swipe actions を設定する
(11:40) list cell では swipe actions は cell の能力です。コンテンツ設定と同じ場所で leadingSwipeActionsConfiguration や trailing 設定を行います。
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Model> { (cell, indexPath, item) in
// @todo configure the cell's content
let markFavorite = UIContextualAction(style: .normal, title: "Mark as Favorite") {
[weak self] (_, _, completion) in
guard let self = self else { return }
// trigger the action with a reference to the model
self.markItemAsFavorite(with: item.identifier)
completion(true)
}
cell.leadingSwipeActionsConfiguration = UISwipeActionsConfiguration(actions: [markFavorite])
}
キーポイント:
- swipe action は list configuration で作られた section に cell が描画されるときだけサポートされます。
- action handler は
indexPathではなくitem.identifierを捕まえます。 - diffable data source の安定 item identifier と iOS 14 の cell registration と相性が良い書き方です。
accessories で cell 機能を宣言する
(14:55) UICollectionViewListCell の accessories は leading または trailing に設定でき、同じ側に複数置けます。一部の accessory は動作を起こします。delete accessory は trailing swipe actions を表示します。
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { (cell, indexPath, item) in
// @todo configure the cell's content
cell.accessories = [
.disclosureIndicator(),
.delete()
]
}
キーポイント:
cell.accessoriesはUICellAccessoryの配列を受け取ります。- システムは disclosure indicator が trailing、delete accessory が leading であることを知っています。
- delete accessory はデフォルトで editing モード時のみ表示され、編集モード出入りのアニメーションは UIKit が処理します。
(15:51) accessory のデフォルト表示ルールはパラメータで調整できます。下の disclosure indicator は非編集時のみ表示します。
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { (cell, indexPath, item) in
// @todo configure the cell's content
cell.accessories = [
.disclosureIndicator(displayed: .whenNotEditing),
.delete()
]
}
キーポイント:
displayed: .whenNotEditingで accessory の表示状態を変えます。- この宣言的設定で cell は通常態と編集態を自動切り替えします。
- 複雑なリストではナビゲーション、削除、並べ替え、outline 展開を同じ cell accessory システムで扱えます。
重要ポイント
- 旧 table view リストを UICollectionView に移行する:外観を変えない設定ページやお気に入りページを作る。リスト configuration で plain、grouped、inset-grouped スタイルを再利用し、その後横おすすめ領域やグリッド section を段階的に追加する。
- iPad sidebar + コンテンツ領域のデータ管理 UI を作る:sidebar または sidebar plain 外観でグループナビを担い、transcript の iPadOS マルチカラム App シーンに適合する。まずナビ列に list configuration を使い、section ごとに横の最近項目や階層グループを追加する。
- リスト項目に安定した swipe actions を追加する:メール、メモ、お気に入りで「お気に入り」「アーカイブ」を実装する。
UICollectionView.CellRegistrationでUIContextualActionを設定し、handler は model か安定 identifier を捕まえる。 - 手書き編集コントロールを accessories に置き換える:フォルダ、タスクリスト、outline に disclosure、delete、reorder などの accessory を追加する。先に
cell.accessoriesを設定し、対応する data source コールバックを接続する。 - section ごとに情報密度を混在させる:1ページで上部に横の最近項目、中央に outline、下部に通常リストを置く。section provider は section ごとにグリッド、直交スクロールレイアウト、
NSCollectionLayoutSection.list(using:layoutEnvironment:)を返せる。
関連セッション
- Advances in UICollectionView — iOS 14 の collection view 更新を高いレベルで紹介。lists、cell registration、section snapshots を含む。
- Advances in diffable data sources — section snapshots、outline collection views、sidebar、item-based reordering を深掘りする。
- Modern cell configuration — list cell のデフォルトコンテンツと状態更新に使う cell content/background configuration を補う。
- Build for iPad — iPad のマルチカラムレイアウト、sidebar、大画面 UI でのリストの使い方を扱う。
コメント
GitHub Issues · utterances