UICollectionView 具有正交滚动和最后一个单元格不同大小的组合布局

问题描述 投票:0回答:1

我们尝试使用

UICollectionView
组合布局来描述部分布局,但这给我们带来了一些麻烦。

我们想要实现的目标:

  • 总共7个细胞
  • 3 个单元格堆叠,每个单元格高度为 30%,宽度为 100%,正交滚动可查看下一个 3 个单元格
  • 当用户到达最后一个单元格时,它将是容器的 100% 高度和 100% 宽度。

下面是不完美示例的 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       |
  //   |                              |
  //   |                              |
  //   |                              |
  //   |                              |
  //   +------------------------------+

Page 1 with the first 3 cells Page 2 with the second 3 cells Page 3 with desired large cell

第三个屏幕截图中的最后一个单元格 (0,6) 是我们想要该部分的 100% 高度的单元格。

有没有办法实现最后一个单元格为截面高度 100% 的布局?

uicollectionview uicollectionviewcompositionallayout
1个回答
1
投票

情侣笔记...

首先:如果您只有恰好 7 个单元格 - 不多也不少 - 这种布局将非常容易在滚动视图中使用堆栈视图来实现。

第二:我只粗略地了解了组合/正交布局,因此很可能有比以下更好的解决方案。但是,它可能值得一看。

第三:您可能已经弄清楚了其中一些内容,但为了清楚起见,我将逐步说明。


因此,使用Apple的实现现代集合视图示例代码,重点关注

OrthogonalScrollingViewController
(我们将部分数量更改为1,项目数量更改为7)。

使用原始的

createLayout()
代码,我们得到这个(如你所知):

enter image description here

第 1 步 - 我认为苹果在命名方面做得非常糟糕,所以我正在改变:

  • leadingItem
    singleItem
  • trailingItem
    doubleItem
  • trailingGroup
    doubleVerticalGroup
  • containerGroup
    repeatingGroup

这对我来说澄清的是,我们定义了一个由两个项目组成的垂直组,以及一个由两个项目组成的水平组(

subitems: [singleItem, doubleVerticalGroup]
),这将重复(当然,结果看起来是一样的) :

enter image description here

第2步我们可以轻松更改顺序,通过交换重复组的

subitems: [doubleVerticalGroup, singleItem])
的顺序:

enter image description here

第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])

外观上没有区别(还):

enter image description here

第 4 步 - 您的布局需要“垂直/垂直/单一”,所以让我们将

repeatingGroup
更改为:

subitems: [doubleVerticalGroup, doubleVerticalGroup, singleVerticalGroup])

我们已经接近我们想要的了:

enter image description here

哎呀! “单一”垂直群体怎么了?好吧,我们将“双垂直组”元素宽度设置为其父级的 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)

我们越来越接近了:

enter image description here

第 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])

我们得到:

enter image description here

第 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])

最终输出是(显示滚动):

enter image description hereenter image description here

enter image description hereenter image description here


我在这里创建了一个 GitHub 存储库:https://github.com/DonMag/AppleModernCollectionViews 包含上述所有内容。

© www.soinside.com 2019 - 2024. All rights reserved.