WWDC Quick Look 💓 By SwiftGGTeam
Advances in UICollectionView

Advances in UICollectionView

观看原视频

Highlight

iOS 14 在 iOS 13 的 Compositional Layout 和 Diffable Data Source 基础上,为 UICollectionView 增加 section snapshots、列表布局、cell registration 和标准 cell configuration,让同一个 collection view 承载网格、outline 与 table view 风格列表。

核心内容

UICollectionView 一开始就把数据、布局和展示分开。数据回答“显示什么”,布局回答“放在哪里”,cell 和 supplementary view 回答“长什么样”。这个拆分让 collection view 很灵活,也让复杂页面的代码容易分散。

iOS 13 给数据侧带来了 Diffable Data Source,给布局侧带来了 Compositional Layout。到了 iOS 14,Apple 沿着这两条线继续补齐能力,并把展示侧的 cell API 也一起更新。演讲里的 Emoji Explorer 是一个缩影:顶部是横向滚动 emoji 网格,中间是可展开收起的 outline,底部是一段看起来像 UITableView 的列表。

如果用旧思路实现这个页面,开发者很可能会在多个 data source、多个 layout 分支和手写 cell 配置之间来回切换。iOS 14 的做法是把这些差异收进同一个 UICollectionView:section snapshot 描述每个 section 的数据,Compositional Layout lists 描述列表外观,cell registration 和 content configuration 负责让 cell 配置变得可复用。

这场 session 是一次总览。它不会把每个 API 都讲到最深,而是把 iOS 14 的 collection view 更新按 Data、Layout、Presentation 三个入口串起来。真正要落地时,10045、10026、10027 三场 session 分别对应这三个方向。

详细内容

Data:用 section snapshot 组合每个 section

03:15)iOS 14 为 Diffable Data Source 增加了 section snapshot。它表示单个 UICollectionView section 的数据,解决两个问题:把 data source 组合成 section 级别的块,以及表达层级数据。

Emoji Explorer 正好有三个不同的 section。横向滚动 emoji 区域用一个 section snapshot 表示,outline 区域用另一个 section snapshot 表示层级数据,列表区域再用第三个 section snapshot 表示。这样一来,一个 collection view 可以同时承载网格、可展开 outline 和普通列表。

关键点:

  • section snapshot 的粒度是单个 section,而不是整个 collection view。
  • outline 能展开和收起,是因为 section snapshot 可以表达父子层级。
  • transcript 明确把 section snapshot 放在 Diffable Data Source 的增强里,后续深入要看 10045。

Layout:用 Compositional Layout 创建列表

06:15)iOS 14 在 Compositional Layout 上增加 Lists。它允许你把 UITableView 风格的 section 放进任何 UICollectionView,并保留 collection view 按 section 混合布局的能力。

let configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
let layout = UICollectionViewCompositionalLayout.list(using: configuration)

关键点:

  • UICollectionLayoutListConfiguration 描述列表外观,这里使用 .insetGrouped
  • UICollectionViewCompositionalLayout.list(using:) 直接生成列表布局。
  • transcript 说明 Lists 建立在 Compositional Layout 之上,所以它可以和其他 layout 按 section 混用。
  • 列表 section 支持 table view 常见能力,包括 swipe actions 和常见 cell layout。

这段代码创建的是所有 section 都是列表的 layout。更复杂的页面可以在 Compositional Layout 的 section provider 中按 section 返回不同布局,把列表、横向滚动区域和自定义网格放在一起。

Presentation:用 Cell Registration 统一 dequeuing 和配置

07:33)旧的 collection view cell 写法通常需要先 register cell class 或 nib,再在 data source 里 dequeue,并把结果转换成具体 cell 类型。iOS 14 的 cell registration 把注册、dequeue 和配置收成一个泛型对象。

// Example of using new iOS 14 cell registration

let reg = UICollectionView.CellRegistration<MyCell, ViewModel> { cell, indexPath, model in
   // configure cell content
}

let dataSource = UICollectionViewDiffableDataSource<S,I>(collectionView: collectionView) {
                     collectionView, indexPath, item -> UICollectionViewCell in
   return collectionView.dequeueConfiguredReusableCell(using: reg, for: indexPath, item: item)
}

关键点:

  • UICollectionView.CellRegistration<MyCell, ViewModel> 同时声明 cell 类型和传入的 model 类型。
  • 闭包会在新 cell 构造出来时执行,用 model 配置 cell。
  • 使用 registration 后,不需要单独调用 register
  • dequeueConfiguredReusableCell(using:for:item:) 从 data source 的 cell provider 中返回已经配置好的 cell。

这个写法和 Diffable Data Source 很合拍。item identifier 负责稳定地表示数据,cell registration 负责把对应 model 映射成 cell 内容。

Presentation:用 UIListContentConfiguration 描述标准 cell 内容

08:32)cell content configuration 提供一组标准布局,效果接近 UITableView 过去的标准 cell 类型。配置对象描述内容,framework 负责布局和性能优化。

var contentConfiguration = UIListContentConfiguration.cell()
contentConfiguration.image = UIImage(systemName:"hammer")
contentConfiguration.text = "Ready. Set. Code"
cell.contentConfiguration = contentConfiguration

关键点:

  • UIListContentConfiguration.cell() 创建标准 cell 内容布局。
  • image 设置左侧图像。
  • text 设置主文本。
  • 把配置赋给 cell.contentConfiguration 后,cell 才会应用这份内容描述。

08:38)如果需要 trailing 侧的辅助文本,可以使用 valueCell()

var contentConfiguration = UIListContentConfiguration.valueCell()
contentConfiguration.image = UIImage(systemName:"hammer")
contentConfiguration.text = "Ready. Set. Code."
contentConfiguration.secondaryText = "#WWDC20"
cell.contentConfiguration = contentConfiguration

关键点:

  • valueCell() 对应主文本加 trailing 辅助文本的布局。
  • secondaryText 是第二段文本,在这个样式里放在 trailing side。
  • 这类配置可以用于 collection view cell,也可以用于 table view 风格的 cell。

08:44)如果辅助文本应该位于主文本下面,可以使用 subtitleCell()

var contentConfiguration = UIListContentConfiguration.subtitleCell()
contentConfiguration.image = UIImage(systemName:"hammer")
contentConfiguration.text = "Ready. Set. Code."
contentConfiguration.secondaryText = "#WWDC20"
cell.contentConfiguration = contentConfiguration

关键点:

  • subtitleCell()secondaryText 放在主文本下方。
  • 同一组 image、text、secondaryText 可以通过不同 factory 方法得到不同排版。
  • transcript 特别说明,这些 configuration 很轻量,只描述内容应该如何呈现。

09:07)同一套思路也应用到 background configuration。它负责 cell 背景,能调整颜色、border style 等属性。内容配置和背景配置组合起来,形成 iOS 14 的现代 cell 配置模型。

核心启发

1. 做一个混合布局的素材浏览器

做什么:顶部放横向滚动的最近素材,中间放可展开的分类 outline,底部放普通列表。

为什么值得做:Emoji Explorer 展示了同一个 collection view 同时承载网格、outline 和列表的模式。这个结构很适合 emoji、图标、模板、照片素材这类有分类又有最近访问记录的内容。

怎么开始:先用 Diffable Data Source 建好稳定 item identifier;每个 section 使用独立 section snapshot;列表区域用 UICollectionLayoutListConfiguration 创建 list section。

2. 把旧 UITableView 页面迁移到 UICollectionView

做什么:把设置页、收藏页或消息列表迁移成 collection view list,先保持原来的 table view 外观。

为什么值得做:Lists 提供 table view 常见外观和 swipe actions,同时保留 collection view 后续混合布局的空间。迁移完成后,你可以逐步添加横向推荐区、网格 section 或 outline。

怎么开始:用 UICollectionLayoutListConfiguration(appearance: .insetGrouped) 创建第一版布局;data source 侧使用 diffable data source;cell 侧改成 UICollectionView.CellRegistration

3. 抽出一套可复用 cell 配置

做什么:为不同列表页统一 image、title、subtitle 和 value 样式,减少每个 view controller 里重复写 cell 配置。

为什么值得做:Cell registration 把 model 到 cell 的映射收在闭包里,content configuration 把标准内容布局收成轻量值类型。它们一起减少了 register、reuse identifier 和手动 subview 布局的重复代码。

怎么开始:按 model 类型创建 UICollectionView.CellRegistration<Cell, Model>;在闭包里选择 UIListContentConfiguration.cell()valueCell()subtitleCell();最后赋值给 cell.contentConfiguration

4. 做一个可展开的目录或侧边栏

做什么:在 iPad app 或文档工具里做一个可展开目录,让文件夹、章节或标签按层级显示。

为什么值得做:section snapshot 的两个目标之一就是表达层级数据,transcript 也把 outline-style UI 作为 iOS 14 的常见视觉设计。

怎么开始:先把每个 section 的根节点和子节点整理成稳定 identifier;用 section snapshot 管理展开状态;需要更深入的展开、收起和 reordering 行为时继续看 10045。

关联 Session

评论

GitHub Issues · utterances