我正在尝试创建一个由一组 2 个项目和另一组 1 个项目组成的组合布局。我希望每个组都占据整个屏幕宽度,并在它们之间进行页面滚动。因此,第一组中的 2 个项目(项目 A)将各自占据屏幕宽度的 50%,第二组中的 1 个项目(项目 B)将占据屏幕宽度的 100%。我将集合视图固定在其超级视图的左右边缘,它占据了整个屏幕。
文本图会显示如下:
[Item A][Item A]|[ Item B ]
“|”在哪里表示屏幕的边缘。因此,根据滚动位置,要么项目 A 都可见,要么项目 B 都可见。滚动结束后,项目 A 和项目 B 永远不应该同时可见。
我使用以下代码进行构图布局:
UICollectionViewCompositionalLayout { sectionIndex, layoutEnvironment in
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
let planItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1))
let planItem = NSCollectionLayoutItem(layoutSize: planItemSize)
let planGroup = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: planItem, count: 2)
let formItem = NSCollectionLayoutItem(layoutSize: groupSize)
let formGroup = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: formItem, count: 1)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [planGroup, formGroup])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPaging
return section
}
上面的代码产生的布局如下所示:
[Item A][Item A]|[Item B]
除了项目 B 的大小设置为屏幕宽度的 50% 而不是 100% 之外,它几乎是正确的。我不知道布局出了什么问题,但它似乎对所有项目都使用
planItemSize
,而不仅仅是项目 A。如何使项目 B 的大小达到屏幕宽度的 100%?
首先,我们可以使用水平流布局
.isPagingEnabled = true
并实现 sizeForItemAt
: 轻松地做到这一点
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let w: CGFloat = collectionView.frame.width
let h: CGFloat = collectionView.frame.height
if indexPath.item % 3 == 2 {
return .init(width: w, height: h)
}
return .init(width: w * 0.5, height: h)
}
我们就完成了:)
但是,既然你问的是
UICollectionViewCompositionalLayout
,那我们就来看看吧。
使用 items、groups 和 sub-groups 时,
.fractionalWidth()
和 .fractionalHeight()
相对于 parent。
由于我们在此布局中的所有高度都使用
100%
,因此我们将重点关注宽度。
对于“基本”布局,
.fractionalWidth(1.0)
将是集合视图宽度的 100%。
使用
.fractionalWidth(0.5)
当然,将是集合视图宽度的 50%。
当我们将项目放入组中时,
count:
会影响大小,并且项目宽度(显然)会被忽略。
因此,如果我们将组设置为
.fractionalWidth(1.0)
(集合视图宽度的100%),并将计数设置为4:
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1))
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 4)
let section = NSCollectionLayoutSection(group: group)
return section
我们会得到这个(红色轮廓是集合视图框架):
我们可以将
itemSize
.fractionalWidth(1.0)
更改为 0.1
、0.5
、2.0
等...它不会改变布局。
在当前代码中,您将
planGroup
和 formGroup
设置为其父级的 100%
宽度 - group
- 也是集合视图宽度的 也 100%
。
因此,只有first组适合,而第二组永远不会被使用。
(我要把
group
改为 mainGroup
以便更容易谈论。)
我们可以做的是将
planGroup
设置为 .fractionalWidth(0.5)
并将 formGroup
设置为 .fractionalWidth(0.5)
...我们就会接近:
但是 - 我们如何让两个项目填充集合视图,然后是一个项目,然后是两个项目,等等?
我们可以将
mainGroup
宽度设置为集合视图宽度的 200%:
现在我们得到了想要的“模式”。请注意,我们需要使用
.paging
而不是 .groupPaging
,因为我们想要按集合视图宽度进行分页:
这是代码的修改版本 - 您应该能够将其直接作为替换:
UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
// main group size is TWICE as wide as the collection view
let mainGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(2.0), heightDimension: .fractionalHeight(1))
// sub-groups
// width is Percentage-of-Parent
// so if each sub-group is one-half the width of the main group
// each will be the Full width of the collection view
let planGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1))
let formGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1))
// because we're putting TWO planItems in planGroup
// CompositionLayout will use 50% of planGroup width for each item
// so planItemSize width is ignored
let planItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1))
let planItem = NSCollectionLayoutItem(layoutSize: planItemSize)
let planGroup = NSCollectionLayoutGroup.horizontal(layoutSize: planGroupSize, subitem: planItem, count: 2)
// because we're putting ONE formItem in formGroup
// CompositionLayout will use 100% of formGroup width
// so formItemSize width is ignored
let formItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1))
let formItem = NSCollectionLayoutItem(layoutSize: formItemSize)
let formGroup = NSCollectionLayoutGroup.horizontal(layoutSize: formGroupSize, subitem: formItem, count: 1)
let mainGroup = NSCollectionLayoutGroup.horizontal(layoutSize: mainGroupSize, subitems: [planGroup, formGroup])
let section = NSCollectionLayoutSection(group: mainGroup)
// use .paging instead of .groupPaging
// because we want to page by collection view Width
section.orthogonalScrollingBehavior = .paging
return section
}