可组合的 UICollectionView 布局:UICollectionViewCompositionalLayout
UICollectionViewCompositionalLayout
是 Apple 在 iOS 13 引入的,用于构建基于组合的 UICollectionView
布局的类。它允许开发者根据一系列的组合布局,更轻松、更灵活地创建复杂的 UICollectionView
布局。
本文主要围绕 UICollectionViewCompositionalLayout
中 “可组合” 这个特性进行讨论。
本文建立在您已经大致了解过
UICollectionViewCompositionalLayout
,知道它是什么,以及基础的用法。下文将不再对其进行讲解。
组合类 FlowLayout 布局
在上一篇文章 NSCollectionLayoutGroup 之子视图的填充 的最后有提到一个场景,这里复用一下这个场景:
在前文中,我有说中间的 “工具Group” 不能使用 subitems
的形式进行初始化,应该使用 subitem + count
的形式初始化 —— 其实这不完全对。
实际需求上,如图这种类 FlowLayout 的布局往往会要求 “每行X个”,即平分展示。
此时如果你们需要考虑下面的场景:
- 屏幕旋转。
- iPad 等屏幕尺寸会发生变化的情况。
- AutoLayout 侧不想要获取屏幕尺寸去计算出 cell 宽度。
那么 subitem + count
就没法做了:subitem + count
会忽略布局方向上的尺寸,所以此时很难单纯用 AutoLayout 做出平分的效果,或者说为了实现平分,需要多次刷新页面布局。
此时有一种用 subitems
实现的方式:以每行/列作为一个 Group,Group 内使用 subitems
。大致的代码如下所示:
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1/4),
heightDimension: .estimated(69)
)
let normalLayoutSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .estimated(500)
)
let toolsListGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: normalLayoutSize,
subitems: [ .init(layoutSize: itemSize) ]
)
let rows = 5
let toolsGroup = NSCollectionLayoutGroup.vertical(
layoutSize: normalLayoutSize,
subitems: [
[toolsTitleItem],
Array(repeating: toolsListGroup, count: rows),
[
toolsFooterItem,
sectionPaddingItem
],
].flatMap { $0 }
)
上面的代码首先定义了2个 Size,一个是 Item 的尺寸,另外一个算是一个 “占位符”。
然后是2个 Group:
toolsListGroup
以行为单位展示 cell。toolsGroup
则是最外面的 Group,它的subitems
包含多个不同的 Group。其中的Array(repeating: toolsListGroup, count: $0)
则是根据行数生成对应数量的 Group。
这种写法有一个注意点还有一个疑惑:
-
注意点是:当 cell 的数量不是行的整数倍的时候,需要手动创建占位 cell。
举例来说,cell 有 5 个,对应的就是2行,cell 分布是 4 + 1。此时因为后面还有其他等待被填充的 Item/Group,如果没有创建占位 cell,则后面的 cell 会被提前,使用toolsListGroup
里的 Item 布局。 -
疑惑的是:我并不知道为什么这么做能生效。
按理说subitems
的布局方式是不会限制内容的数量的,那么为什么它能每行正好装4个(就这个例子来说,每个Cell的宽度是屏幕的1/4),下一行的 Cell 则使用下一个 Group 的布局?
有关于 UICollectionViewCompositionalLayout
组合复杂布局的文档还是太少,目前还没找到这么做能生效的原因。