我们尝试使用
UICollectionView
组合布局来描述部分布局,但这给我们带来了一些麻烦。
我们想要实现的目标:
下面是不完美示例的 ASCII 艺术和屏幕截图。
我们的出发点是苹果的示例代码,特别是
OrthogonalScrollingViewController
,但我们发现如果我们扩大那里的宽度,高度设置似乎不再受到尊重。
我们尝试过的最基本的布局版本是这样的:
func createLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout {
(sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
// Small items at roughly 30% of the container height.
let smallItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(0.3)
)
)
// The large item should be 100% of the container width.
let largeItem = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)
)
)
// We want 3 items to appear stacked with orthogonal scrolling.
let smallItemGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)
),
subitem: smallItem,
count: 3
)
let containerGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(0.5)
),
subitems: [smallItemGroup, largeItem]
)
let section = NSCollectionLayoutSection(group: containerGroup)
section.orthogonalScrollingBehavior = .paging
return section
}
return layout
}
我们尝试了嵌套组的多种变体并使用
.vertical
和 .horizontal
初始化器,但每个都具有相同的结果:最后一个单元格始终与所有其他单元格大小相同。
// +------------------------------+ These would be off-screen
// | +-------------------------+ | +-------------------------+ +-------------------------+
// | | 1 | | | 4 | | |
// | +-------------------------+ | +-------------------------+ | |
// | +-------------------------+ | +-------------------------+ | |
// | | 2 | | | 5 | | 7 |
// | +-------------------------+ | +-------------------------+ | |
// | +-------------------------+ | +-------------------------+ | |
// | | 3 | | | 6 | | |
// | +-------------------------+ | +-------------------------+ +-------------------------+
// | |
// | |
// | |
// | rest of the screen |
// | |
// | |
// | |
// | |
// +------------------------------+
第三个屏幕截图中的最后一个单元格 (0,6) 是我们想要该部分的 100% 高度的单元格。
有没有办法实现最后一个单元格为截面高度 100% 的布局?
情侣笔记...
首先:如果您只有恰好 7 个单元格 - 不多也不少 - 这种布局将非常容易在滚动视图中使用堆栈视图来实现。
第二:我只粗略地了解了组合/正交布局,因此很可能有比以下更好的解决方案。但是,它可能值得一看。
第三:您可能已经弄清楚了其中一些内容,但为了清楚起见,我将逐步说明。
因此,使用Apple的实现现代集合视图示例代码,重点关注
OrthogonalScrollingViewController
(我们将部分数量更改为1,项目数量更改为7)。
使用原始的
createLayout()
代码,我们得到这个(如你所知):
第 1 步 - 我认为苹果在命名方面做得非常糟糕,所以我正在改变:
leadingItem
至 singleItem
trailingItem
至 doubleItem
trailingGroup
至 doubleVerticalGroup
containerGroup
至 repeatingGroup
这对我来说澄清的是,我们定义了一个由两个项目组成的垂直组,以及一个由两个项目组成的水平组(
subitems: [singleItem, doubleVerticalGroup]
),这将重复(当然,结果看起来是一样的) :
第2步我们可以轻松更改顺序,通过交换重复组的
subitems: [doubleVerticalGroup, singleItem])
的顺序:
第3步 - 我发现拥有一个单个项目和一个垂直项目组有点令人困惑,所以我将把单个项目单独“嵌入”到一个垂直组中:
// let's create a "singleVerticalGroup" - based on "doubleVerticalGroup"
let singleVerticalGroup = NSCollectionLayoutGroup.vertical(
// width is percentage of "parent"
// height is percentage of "parent"
// subitem is 1 singleItem (count: 1), arranged vertically
// width of this group is what the singleItem width used to be
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.7),
heightDimension: .fractionalHeight(1.0)),
subitem: singleItem, count: 1)
并将我们的
repeatingGroup
项目更改为:
subitems: [doubleVerticalGroup, singleVerticalGroup])
外观上没有区别(还):
第 4 步 - 您的布局需要“垂直/垂直/单一”,所以让我们将
repeatingGroup
更改为:
subitems: [doubleVerticalGroup, doubleVerticalGroup, singleVerticalGroup])
我们已经接近我们想要的了:
哎呀! “单一”垂直群体怎么了?好吧,我们将“双垂直组”元素宽度设置为其父级的 30%,将“单垂直组”元素宽度设置为其父级的 70%……所以现在我们有:
30% 30% 70%
当然,这不适合 100%...所以,
第 5 步 - 让我们将元素宽度设置为 1/3
let fWidth: CGFloat = 1.0 / 3.0
let singleVerticalGroup = NSCollectionLayoutGroup.vertical(
// width of this group is now 1/3
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(fWidth),
heightDimension: .fractionalHeight(1.0)),
subitem: singleItem, count: 1)
let doubleVerticalGroup = NSCollectionLayoutGroup.vertical(
// width of this group is now 1/3
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(fWidth),
heightDimension: .fractionalHeight(1.0)),
subitem: singleItem, count: 2)
我们越来越接近了:
第 6 步 - 您的设计需要 3 项垂直堆叠,而不是 2,所以我们将其命名为
tripleVerticalGroup
并将 count: 2
更改为 count: 3
:
let tripleVerticalGroup = NSCollectionLayoutGroup.vertical(
// subitem is 3 singleItems, arranged vertically
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(fWidth),
heightDimension: .fractionalHeight(1.0)),
subitem: singleItem, count: 3)
和我们的
repeatingGroup
项目:
let repeatingGroup = NSCollectionLayoutGroup.horizontal(
// width is percentage of "parent"
// height is percentage of "parent"
// subitem is now 3 "groups" arranged horiztonally ...
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.85),
heightDimension: .fractionalHeight(0.4)),
subitems: [tripleVerticalGroup, tripleVerticalGroup, singleVerticalGroup])
我们得到:
第 7 步 - 我们需要做的最后一件事是调整布局,以便
repeatingGroup
中的每个元素填充视图的宽度。
我们注意到使用的
repeatingGroup
布局尺寸:
widthDimension: .fractionalWidth(0.85)
所以让我们将其更改为 视图宽度的 3 倍(其父视图):
let repeatingGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(3.0),
heightDimension: .fractionalHeight(0.4)),
subitems: [tripleVerticalGroup, tripleVerticalGroup, singleVerticalGroup])
最终输出是(显示滚动):
我在这里创建了一个 GitHub 存储库:https://github.com/DonMag/AppleModernCollectionViews 包含上述所有内容。