- 使用的技术: compositional layout diffable data source。ios 14 。
- 创建 layout 以描述布局;
- 创建 datasource 以提供数据和 view:
- 使用 cellregistration 和 dequeueconfiguredreusablecell 来获取 cell;
- 使用 supplementaryregistration 和 dequeueconfiguredreusablesupplementary 来获取 header、footer 等 supplementary views。
如上图所示,一个 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: nscollectionlayoutcontainer
contentsize: cgsize
effectivecontentsize: cgsize
:content insets 生效之后的 sizecontentinsets: nsdirectionaledgeinsets
effectivecontentinsets: nsdirectionaledgeinsets
traitcollection: uitraitcollection
list layout
compositional layout 专门提供了一个接口来创建 list layout:
static func list(using: uicollectionlayoutlistconfiguration) -> uicollectionviewcompositionallayout
uicollectionlayoutlistconfiguration 用于配置 list layout 的一些属性,构造函数中需要指定一个 appearance,如 .plain
,.sidebar
,.grouped
等。参见 来查看可配置的属性,下面列出几种。
- headermode
.none
:不展示 header;.supplementary
:使用 supplementary views 来展示 headers;.firstiteminsection
:使用 section 中的第一个 item 来作为 header。
创建 datasource 的时候,需要传入一个 cellprovider 来提供 cell view:
datasource = uicollectionviewdiffabledatasource(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 { cell, indexpath, item in
var contentconfiguration = cell.defaultcontentconfiguration()
contentconfiguration.text = "\(item)"
contentconfiguration.textproperties.color = .lightgray
cell.contentconfiguration = contentconfiguration
}
datasource = uicollectionviewdiffabledatasource(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 具体可参见 。
header、footer 等 supplementary views 的配置和 cell 类似,设置 datasource 的 supplementaryviewprovider 属性来提供用于创建 view 的闭包,在闭包里面调用 dequeueconfiguredreusablesupplementary 来获取一个复用的 view,该方法接受一个闭包参数 supplementaryregistration 来配置 view。