如何使用集合视图组成布局将单元格置于集合视图内部

时间:2020-10-27 10:50:02

标签: ios swift

我要执行以下任务:我需要在电影屏幕上实现我的视图,其中有一个屏幕和一个座位集合,其中每一行代表一个区域:enter image description here

数据来自代表席位的二维数组:

var seats = [[1, 2, 3, 4, 5],
             [1, 2, 3, 4, 5],
            [1, 2, 3, 4, 5, 6],
            [1, 2, 3, 4, 5, 6],
            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
]

问题在于,我似乎无法找到如何使用合成布局将单元格集中在集合视图中的中心。这是管理布局的代码:

private func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout { [weak self] (section, configuration) -> NSCollectionLayoutSection? in
            guard let self = self else { return nil }
            
            // get the max seat number
            let max = CGFloat(self.seats.compactMap { $0.max() }.max()!)

            let itemSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0 / max),
                heightDimension: .fractionalHeight(0.5))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            item.contentInsets = .init(top: 2, leading: 2, bottom: 2, trailing: 2)

            let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                                                         heightDimension: .fractionalWidth(0.2))

            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

            let section = NSCollectionLayoutSection(group: group)
            section.contentInsets = .init(top: 16, leading: 32, bottom: 0, trailing: 32)
            
            return section
        }
        
        let config = UICollectionViewCompositionalLayoutConfiguration()
        config.interSectionSpacing = -50
        layout.configuration = config
        
        return layout
    }

我设法使用“老式”集合视图流布局来实现此行为,如下所示:

enter image description here

很明显,我无法使用collectionView:layout:insetForSectionAtIndex:之类的“集合视图流布局”方法来进行计算,因此任何想法都将不胜感激!

2 个答案:

答案 0 :(得分:2)

让每行或至少每组具有相同项目数的行成为其自己的部分,并为布局提供部分提供者功能。为节提供者功能提供了节号以及环境对象。从该环境对象,您可以了解集合视图的宽度。现在,只需给组或部分适当的插图即可。

为了说明这一点,我能够实现这样的布局(三个部分,每个部分的项目数是部分索引加1):

enter image description here

我不会让你处于悬念状态;我将仅向您显示该布局的代码。不好看我使用了一堆硬编码的值。这个想法只是生成布局以便向您展示一般原理。但我敢肯定,您可以看到如何根据自己的情况对此进行调整:

let config = UICollectionViewCompositionalLayoutConfiguration()
config.scrollDirection = .vertical
let inter = 5 as CGFloat
config.interSectionSpacing = 5
let layout = UICollectionViewCompositionalLayout(sectionProvider: { ix, environment in
    let side = 30 as CGFloat
    let cellsz = NSCollectionLayoutSize(widthDimension: .absolute(side), heightDimension: .fractionalHeight(1))
    let cell = NSCollectionLayoutItem(layoutSize: cellsz)
    let groupsz = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(side))
    let count = ix+1
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupsz, subitems: [cell])
    group.interItemSpacing = .fixed(inter)
    let sec = NSCollectionLayoutSection(group: group)
    let width = environment.container.contentSize.width
    let inset = (width - CGFloat(count)*side - (CGFloat(count)-1)*inter) / 2.0
    sec.contentInsets = .init(top: 0, leading: inset, bottom: 0, trailing: 0)
    return sec
}, configuration: config)

这可能不是唯一的方法;我想您可以改为呼叫NSCollectionLayoutGroup.custom并手动布置单元格。但是我认为这不是一个坏办法。

我还应该说,我不认为收集视图是获得想要达到的结果的最佳方法。您最好做的就是直接在代码中直接布置座位视图。

答案 1 :(得分:0)

我在实现自己的键盘时遇到了同样的问题。我的结果:Keyboard images。这就是我在不使用常量的情况下做到的(Matt 很棒的答案的改进)。

  private func generateKeyboardLayout() -> UICollectionViewLayout {

    let groupInset = 3 / UIScreen.main.scale
    let layout = UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in
      let item = NSCollectionLayoutItem(
        layoutSize: NSCollectionLayoutSize(
          widthDimension: .fractionalWidth(1.0),
          heightDimension: .fractionalHeight(1.0)))
      
      let group = NSCollectionLayoutGroup.horizontal(
        layoutSize: NSCollectionLayoutSize(
          widthDimension: .fractionalWidth(1/10),
          heightDimension: .fractionalHeight(1/3)),
        subitems: [item])
      group.contentInsets = NSDirectionalEdgeInsets(top: groupInset, leading: groupInset, bottom: groupInset, trailing: groupInset)
      
      let count = Keyboard.getItems(at: keyboardSection).count
      let containerWidth = layoutEnvironment.container.contentSize.width
      let groupWidthDimension = group.layoutSize.widthDimension.dimension
      let itemWidth = containerWidth * groupWidthDimension
      let inset = (containerWidth - CGFloat(count) * itemWidth) / 2.0
  
      let section = NSCollectionLayoutSection(group: group)
      section.contentInsets = .init(top: 0, leading: round(inset), bottom: 0, trailing: 0)
      section.orthogonalScrollingBehavior = .continuous
      return section
    }
    return layout
  }

count 表示每行的项目数

let count = Keyboard.getItems(at: keyboardSection).count

containerWidth 是 CGFloat 中视图的确切宽度

let containerWidth = layoutEnvironment.container.contentSize.width

groupWidthDimension 是每个组/键盘磁贴的宽度,包括应用的插图

let groupWidthDimension = group.layoutSize.widthDimension.dimension

itemWidth 为您提供每个键盘图块的确切大小

let itemWidth = containerWidth * groupWidthDimension

inset(前导)是根据containerWidth的差值和所有items的宽度之和然后减半计算的

let inset = (containerWidth - CGFloat(count) * itemWidth) / 2.0
section.contentInsets = .init(top: 0, leading: round(inset), bottom: 0, trailing: 0)