Slide 1

Slide 1 text

What’s new in UICollectionView Masaki Haga

Slide 2

Slide 2 text

~ iOS 12のUICollectionView - performBatchUpdate(_:completion:)を呼んでData不整合によりCrash - 親ViewControllerのViewのSizeに合わせたCellのSize指定が案外めんどくさい - 縦CollectionViewの中に横スクロールのCollectionViewを何個か入れたいが Scroll位置の保存などわりとめんどくさい

Slide 3

Slide 3 text

新しいUICollectionView - Data Source - Layout

Slide 4

Slide 4 text

Apple公式のコード Using Collection View Compositional Layouts and Diffable Data Sources

Slide 5

Slide 5 text

Data Source - [Old] UICollectionViewDataSource - reloadData() or performBatchUpdate(:_completion:) - UICollectionViewDiffableDataSource & NSDiffableDataSourceSnapshot - apply() - collectionViewへの差分反映はFramework側でhandleしてもらえるようになった。

Slide 6

Slide 6 text

古いData Sourceの宣言 - Data Source ObjectをUICollectionViewDataSourceに準拠 - collectionViewのdatasourceにData Source Objectをset - collectionView.reloadData()

Slide 7

Slide 7 text

新しいData Sourceの宣言 - UICollectionViewDiffableDataSourceをUICollectionViewとCellProviderを引数 に初期化する。(Delegate型ではなくClosure型のCallback) - State(NSDiffableDataSourceSnapshot)をapplyしてCollectionViewに反映 public typealias CellProvider = (UICollectionView, IndexPath, ItemIdentifierType) -> UICollectionViewCell?

Slide 8

Slide 8 text

注意 - Snapshotに渡すSectionの値と、Itemの値はHashable - SnapshotはHashValueによって値の同一性を認識する。 - つまり、HashableのDefaultの実装だと、propertyの変更だけで違うItemであると 認識されてしまう。

Slide 9

Slide 9 text

こんなかんじ struct VideoCollection: Hashable { var title: String let videos: [Video] let identifier = UUID() func hash(into hasher: inout Hasher) { hasher.combine(identifier) } }

Slide 10

Slide 10 text

SwiftUI - DifferenceUpdateがデフォルト - StateはHashableではなくIdentifiableに準拠する

Slide 11

Slide 11 text

Diffアルゴリズムはどこからくるのか UICollectionViewDiffableDataSourceの実装はわからないけれども、 Swift5.1からDiff関係のAPIが増えているのでおそらくそれらを使っているのでは。 Swift Evolution: Ordered Collection Diffing

Slide 12

Slide 12 text

New API - BidrectionalColleciton: difference(from:) - Swift Standard Library: CollectionDifference - Foundation: NSOrderedCollectionDifference - _CollectionChanges

Slide 13

Slide 13 text

Layout - [Old] UICollectionViewFlowLayout + UICollectionViewDelegateFlowLayout - New APIs - UICollectionViewCompositionalLayout - NSCollectionLayoutSection - NSCollectionLayoutGroup - NSCollectionLayoutItem - NSCollectionLayoutSize - Section > Group > Item

Slide 14

Slide 14 text

古いLayoutの宣言 - UICollectionViewFlowLayout もしくはCustom UICollectionViewLayout - Delegateからサイズ情報などを返す

Slide 15

Slide 15 text

新しいLayoutの宣言 - UICollectionViewCompositionalLayout - initの引数として、NSCollectionLayoutSectionか、SectionProviderというClosureを渡す。 public typealias UICollectionViewCompositionalLayoutSectionProvider = (Int, NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? NSCollectionLayoutEnvironmentというので親CollectionViewの情報(ContentSize等)をとってくることができ る。SwiftUIでもGemetryReaderというのがあって、同じアプローチをとっているところが面白い。

Slide 16

Slide 16 text

Nested Collection View

Slide 17

Slide 17 text

Nested Collection View 縦スクロールの中の横スクロールが簡単に書けるようになった。 let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .continuous UIKit側で_UICollectionViewOrthogonalScrollerEmbeddedScrollView的な ScrollViewを勝手にいれてくれる。 画面外から戻ってきてももとのContentOffsetが保存されている。

Slide 18

Slide 18 text

Reference - Advances in Collection View Layout - Advances in UI Data Sources