[Swift]UICollectionViewの進化:Compositional Layouts編
経緯
iOS13から大きく変更されたCollectionViewですが、
特に影響の大きいCompositional Layouts
とDiffable Data Source
について、
しっかりと理解をしておきたかった為。
何が変わったのか
これまでのCollectionViewの構築方法がどう変化したか、
個人的な重要点であるLayout
とData Source
をピックアップして紹介します。
この記事ではまずLayout
に関する変更点をまとめています。
Data Source
に関しての記事はこちら
参考資料としているWWDCのスライド資料です。
Layout
これまで主にLayoutで使用されてきたクラスは、
UICollectionViewFlowLayout
このクラスかと思います。
ただこのクラスでは昨今の複雑なレイアウトを作成するのに、
以下のようにいくつか課題がありました。
- Boilerplate code: ボイラープレート・コード
- Performance considerations: パフォーマンスへの配慮
- Supplementary and decoration view challenges: 補足・装飾表示の課題
- Self-sizing challenges: セルフサイジングの課題
その解決策として登場したのが、Compositional Layouts
です。
Compositional Layouts
Compositional Layouts
とは以下のように紹介されています
- Composing small layout groups together:小さなレイアウトグループをまとめて合成
- Layout groups are line-based:レイアウトグループはラインベース
- Composition instead of subclassing:サブクラス化ではなくコンポジション化
以下公式サンプルコードとスライドからCompositional Layouts
の構成を理解していきます。
// Create a List by Specifying Three Core Components: Item, Group and Section
let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(44.0))
let item = NSCollectionLayoutItem(layoutSize: size)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
let layout = UICollectionViewCompositionalLayout(section: section)
Item > Group > Section > Layoutという階層構造になっており、
全体のサイズを決定しているのがサンプルコードのsize
プロパティになります。
ここからさらに細かくその構造に使用されているClassを見て理解を深めましょう。
NSCollectionLayoutSize
全てのレイアウトはサイズが明示されていて、
幅と高さの寸法から構成されます。
class NSCollectionLayoutSize {
init(widthDimension: NSCollectionLayoutDimension,
heightDimension: NSCollectionLayoutDimension)
}
じゃあその寸法(以下Dimension)はどういう構成になっているかというと、
以下のように4つの定義方法があります。
class NSCollectionLayoutDimension {
class func fractionalWidth(_ fractionalWidth: CGFloat) -> Self
class func fractionalHeight(_ fractionalHeight: CGFloat) -> Self
class func absolute(_ absoluteDimension: CGFloat) -> Self
class func estimated(_ estimatedDimension: CGFloat) -> Self
}
順に4つの違いや特徴を見ていきましょう。
fractionalWidth、fractionalHeight
画面サイズに対しての比率の割合を指定できます。
①fractionalWidth
①このスライド例では、
画面サイズに対しての比率が0.5なので画面サイズの半分のwidthとなります。
②fractionalHeight
②このスライド例では、
画面サイズに対しての比率が0.3なので画面サイズの30%のheightとなります。
③fractionalWidth + fractionalHeight
③このスライド例では、
widthとheightの両方にfractionalWidth0.25を設定しています。
そのためwidthとheightの大きさは同等となります。
absolute,estimated
fractionalWidth、fractionalHeight
が画面サイズに対しての比率の割合でしたが、
absolute,estimated
はabsolute pointで値を指定できます。
absolute
absoluteの場合は固定の絶対値を指定します。
他の制約があってもこちらを優先します。
estimated
estimatedの場合も値を指定出来ますが、
他の制約があった場合は制約が優先されます。
NSCollectionLayoutItem
Compositional Layouts
の階層構造の最小部品のitem
ですが、
生成時に前述したNSCollectionLayoutSize
を設定する必要があります。
class NSCollectionLayoutItem {
convenience init(layoutSize: NSCollectionLayoutSize)
var contentInsets: NSDirectionalEdgeInsets
}
またitem
の使い道としてはCellやヘッダーやフッターなどの補足ビューです。
ただ個人的にはヘッダーやフッターなどは、
NSCollectionLayoutBoundarySupplementaryItem
で、
定義することが多いイメージを持っています。
NSCollectionLayoutGroup
group
はレイアウトの基本単位を構成します。
以下3つの形で定義することが可能になり、カスタム性が向上しました。
horizontal, vertical, custom
第2引数のsubitems
には前途したNSCollectionLayoutItem
をセットします。
NSCollectionLayoutSection
section
は図の緑の枠の部分になります。
section
でよく使われるプロパティを、いくつか紹介します。
interGroupSpacing
セクション内でのグループ間のスペースを設定出来るプロパティです。
contentInsets
セクションのコンテンツとその境界の間のスペースを設定出来るプロパティです。
boundarySupplementaryItems
セクションの境界部分に関連する、
ヘッダーまたはフッターを追加するために使用されるオブジェクトの配列です。
なのでヘッダーまたはフッターを使用する際によく使用されます。
decorationItems
背景など、セクションに固定される装飾アイテムの配列です。
よく背景を設定する際に使用されます。
UICollectionViewCompositionalLayout NSCollectionViewCompositionalLayout
これまでItem
Group
Section
挙げてきました。
最後にLayout
の部分となります。
initでの生成方法がに4種類あり、以下のように使い分けが出来ます。
ここで言うconfigurationは、例えばセクション間のスペースを設定したい場合など、
レイアウトのスクロール方向、セクション間隔、ヘッダまたはフッタを定義するオブジェクトです。
UICollectionViewCompositionalLayoutConfiguration
- 単一セクションの場合
init(section: NSCollectionLayoutSection)
- 単一セクションかつ追加のconfigurationがある場合
init(section:NSCollectionLayoutSection,configuration:UICollectionViewCompositionalLayoutConfiguration)
- 複数セクションでセクション単位でレイアウトの設定をしたい場合
init(sectionProvider: UICollectionViewCompositionalLayoutSectionProvider)
- 複数セクションでセクション単位でレイアウトの設定をしたいかつ追加のconfigurationがある場合
init(sectionProvider: UICollectionViewCompositionalLayoutSectionProvider, configuration: UICollectionViewCompositionalLayoutConfiguration)
Compositional Layoutの感想
UICollectionViewFlowLayout
の課題点をうまく解消出来ていると思います。
より小さなレイアウト部分まで設定することが可能になり、
使用するAPIもほとんど統一されているので1度流れを覚えたら使いやすく感じると思います。
続き
Data Source
に関しての記事はこちら
Discussion