iOS Modern Collection View
TL;DR
- 使用的技术: Compositional layout + Diffable data source。iOS 14+。
- 创建 layout 以描述布局;
- 创建 dataSource 以提供数据和 view:
- 使用 CellRegistration 和 dequeueConfiguredReusableCell 来获取 cell;
- 使用 SupplementaryRegistration 和 dequeueConfiguredReusableSupplementary 来获取 header、footer 等 supplementary views。
Compositional Layout

如上图所示,一个 compositional layout 由若干个 section 组成,每个 section 又由若干个 group 组成,每个 group 又包含若干个 item,因此,创建一个 layout 的过程即先创建最小展示单元 item 开始,再创建 group,创建 section,创建 layout:
func createBasicListLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(44)
)
let group = NSCollectionLayoutGroup.horizontal(
layoutSize: groupSize,
subitems: [item]
)
let section = NSCollectionLayoutSection(group: group)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
SectionProvider
如果需要多个布局不同的 sections,可以用下面的构造函数来创建 layout:
// UICollectionViewCompositionalLayout
init(
sectionProvider: @escaping UICollectionViewCompositionalLayoutSectionProvider,
configuration: UICollectionViewCompositionalLayoutConfiguration
)
其中闭包 sectionProvider 用于创建并返回 layout 的各个 secitons,声明如下:
typealias UICollectionViewCompositionalLayoutSectionProvider = (Int, NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection?
// arguments meaning: { sectionIndex, layoutEnvironment in ... }
该闭包也会在一些系统事件触发时被调用,如横竖屏切换、系统字体变更、iPad multitasking 引发的 size class 变更等,可以访问 layoutEnvironment 来获取相关信息,以适配这些场景。
LayoutConfiguration
UICollectionViewCompositionalLayoutConfiguration
scrollDirection: UICollectionView.ScrollDirection- 滚动方向:
.vertical|.horizontal
- 滚动方向:
interSectionSpacing: CGFloat- Sections 之间的间距
contentInsetsReference: UIContentInsetsReference- 定义 content inset 时的参考边界
.automatic|.none|.safeArea|.layoutMargins|.readableContent
- 红色为 safeArea,绿色为 layoutMargins,蓝色为 readableContent
boundarySupplementaryItems: [NSCollectionLayoutBoundarySupplementaryItem]- 在整个 layout 边界处的一些附加 items,如全局 header、全局 footer、badge 等
LayoutEnvironment
包含 layout container 和 environment traits 的信息
container: NSCollectionLayoutContainercontentSize: CGSizeeffectiveContentSize: CGSize:content insets 生效之后的 sizecontentInsets: NSDirectionalEdgeInsetseffectiveContentInsets: NSDirectionalEdgeInsets
traitCollection: UITraitCollection
List layout
Compositional layout 专门提供了一个接口来创建 list layout:
static func list(using: UICollectionLayoutListConfiguration) -> UICollectionViewCompositionalLayout
UICollectionLayoutListConfiguration 用于配置 list layout 的一些属性,构造函数中需要指定一个 appearance,如 .plain,.sidebar,.grouped 等。参见 Apple 文档 来查看可配置的属性,下面列出几种。
- headerMode
.none:不展示 header;.supplementary:使用 supplementary views 来展示 headers;.firstItemInSection:使用 section 中的第一个 item 来作为 header。
Cell view 和 supplementary view 的获取
创建 dataSource 的时候,需要传入一个 cellProvider 来提供 cell view:
dataSource = UICollectionViewDiffableDataSource<Int, UUID>(collectionView: collectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, itemIdentifier: UUID) -> UICollectionViewCell? in
// Configure and return cell.
}
之前我们需要调用 register 方法来注册所需要的 cell 类,然后在 cellProvider 中调用 dequeueReusableCell 方法来获取复用的 cell。iOS 14 提供了一组新的方法,通过 CellRegistration 来配置 cell,然后使用 dequeueConfiguredReusableCell 方法来获取复用的 cell,在调用该方法的时候会自动将 cell 注册到 collectionView 上。如:
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { cell, indexPath, item in
var contentConfiguration = cell.defaultContentConfiguration()
contentConfiguration.text = "\(item)"
contentConfiguration.textProperties.color = .lightGray
cell.contentConfiguration = contentConfiguration
}
dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: collectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, itemIdentifier: Int) -> UICollectionViewCell? in
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration,
for: indexPath,
item: itemIdentifier)
}
注意不要在 cellProvider 里面创建 cell registration,会造成 cell 无法复用,且在 iOS 15+ 上直接报异常
对 cell 的配置通过 UIListContentConfiguration 来完成,调用 cell 的 defaultContentConfiguration 来获取一个包含一些预设属性的 configuration,根据传入的数据对其进行配置,然后再赋值回 cell 的 contentConfiguration。设置 contentConfiguration 会替换掉 cell 现有的 contentView。Cell configuration 具体可参见 Modern cell configuration (WWDC20 10027)。
Header、footer 等 supplementary views 的配置和 cell 类似,设置 dataSource 的 supplementaryViewProvider 属性来提供用于创建 view 的闭包,在闭包里面调用 dequeueConfiguredReusableSupplementary 来获取一个复用的 view,该方法接受一个闭包参数 SupplementaryRegistration 来配置 view。
References
- https://www.vbutko.com/articles/how-to-create-uicollectionview-list-with-compositional-layout/
- https://jeandavidpeirolo.medium.com/how-uilayoutguide-can-help-you-manage-ui-complexity-8e911c9bcdd7
iOS Modern Collection View的更多相关文章
- Collection View Programming Guide for iOS---(一)----About iOS Collection Views
Next About iOS Collection Views 关于iOS Collection Views A collection view is a way to present an orde ...
- IOS UIView 03- 自定义 Collection View 布局
注:本人是翻译过来,并且加上本人的一点见解. 前言 UICollectionView 在 iOS6 中第一次被引入,也是 UIKit 视图类中的一颗新星.它和 UITableView 共享一套 API ...
- iOS系列译文:自定义Collection View布局
原文出处: Ole Begemann 译文出处: 黄爱武(@answer-huang).欢迎加入技术翻译小组. UICollectionView在iOS6中第一次被介绍,也是UIKit视图类中的一 ...
- Collection View Programming Guide for iOS---(七)---Custom Layouts: A Worked Example
Custom Layouts: A Worked Example Creating a custom collection view layout is simple with straightfor ...
- Collection View Programming Guide for iOS---(五)---Incorporating Gesture Support
Incorporating Gesture Support 结合手势支持 You can add greater interactivity to your collection views th ...
- Collection View Programming Guide for iOS---(三)---Designing Your Data Source and Delegate
Designing Your Data Source and Delegate 设计你的数据源和委托 Every collection view must have a data source o ...
- Collection View 自定义布局(custom flow layout)
Collection view自定义布局 一般我们自定义布局都会新建一个类,继承自UICollectionViewFlowLayout,然后重写几个方法: prepareLayout():当准备开始布 ...
- iOS—使用picker View
iOS—使用picker View 一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162,不可修改. 2.显示数据,需要设置 ...
- 自定义 Collection View 布局
自定义 Collection View 布局 answer-huang 29 Mar 2014 分享文章 UICollectionView 在 iOS6 中第一次被引入,也是 UIKit 视图类中的一 ...
- Collection View Programming Guide for iOS---(六)---Creating Custom Layouts
Creating Custom Layouts 创建自定义布局 Before you start building custom layouts, consider whether doing so ...
随机推荐
- 二进制安装Kubernetes(k8s) v1.27.3 IPv4/IPv6双栈 可脱离互联网
二进制安装Kubernetes(k8s) v1.27.3 IPv4/IPv6双栈 可脱离互联网 https://github.com/cby-chen/Kubernetes 开源不易,帮忙点个star ...
- NC20115 [HNOI2015]菜肴制作
题目链接 题目 题目描述 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号 ...
- APB_AHB_AXI协议的简单介绍
一.AMBA概述 今天要介绍的三种嵌入式总线技术:APB.AHB.AXI,它们都属于AMBA 片上总线协议.所以,在介绍这几种总线技术之前,有必要先了解一下AMBA 片上总线协议是什么. AMBA ( ...
- es6 快速入门 系列 —— Symbol
其他章节请看: es6 快速入门 系列 Symbol es6新增的一种原始类型 试图解决的问题 唯一的属性名 给对象新增一个属性,如何保证这个属性名是独一无二的? 更改 instanceof 的运行方 ...
- MySQL的MVCC概念介绍(转)
并发字段修改业务 最近在主要在做"工作流引擎"课题的预研工作,在涉及到"会签任务"(工作流业务概念,这与我们今天讨论文问题没有太多关联)的时候,遇到了一个并发修 ...
- Java定时器(Timer)
1.介绍 Timer和TimerTask是用于在后台线程中调度任务的java util类.简单地说,TimerTask是要执行的任务,Timer是调度器. 2.调度一次性任务 2.1 指定延迟后执行 ...
- maven打包时打包指定的lib文件夹
今天在打包自己的spring boot项目时遇到了问题, 报找不到类和符号. 因为我有些依赖是放在项目lib文件夹中,那么打包的时候要连把它一起打包. 修改pom.xml, 添加一下内容: <b ...
- Golang Web 框架 Gin 基础学习教程集合目录
Gin Web 框架基础学习系列目录 01-quickstart 02-parameter 03-route 04-middleware 05-log 06-logrus 07-bind 08-val ...
- JVM类的加载和加载器
JVM类的加载和类的加载器 一.类的加载过程 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来 ...
- 【Azure 应用服务】在Azure App Service for Windows 中部署Java/NodeJS/Python项目时,web.config的配置模板内容
问题描述 在Azure App Service for Windows 中部署web项目时候,需要在wwwroot下设置web.config,对于不同语言的项目,web.config文件中的httpP ...