简体   繁体   English

"如何使用集合视图组合布局使集合视图内的单元格居中"

[英]How to center cells inside collection view using collection view compositional layout

I have the following task at work: I need to implement the cinema view where I have a screen and a collection of seats where each row represents a section:我有以下工作任务:我需要实现电影院视图,其中有一个屏幕和一组座位,每行代表一个部分: 在此处输入图像描述<\/a>

Data is coming from a 2-dimensional array that represents the seats:数据来自代表座位的二维数组:

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

Let each row, or at least each set of rows with the same number of items, be its own section, and give the layout a section provider function.让每一行,或者至少每组具有相同数量项目的行,成为它自己的部分,并为布局提供一个部分提供者功能。 The section provider function is given the section number along with an environment object.段提供者函数被赋予段号以及环境对象。 From that environment object, you can learn the width of the collection view.从该环境对象中,您可以了解集合视图的宽度。 Now just give the group or section appropriate insets.现在只需给组或部分适当的插图。

To illustrate, I was able to achieve a layout like this (three sections, number of items per section is the section index plus one):为了说明,我能够实现这样的布局(三个部分,每部分的项目数是部分索引加一):

在此处输入图片说明

And I won't keep you in suspense;我不会让你悬念; I'll just show you the code for that layout.我只会向您展示该布局的代码。 It isn't pretty;它不漂亮; I used a bunch of hard-coded values.我使用了一堆硬编码值。 The idea was just to generate the layout so as to show you the general principles.这个想法只是生成布局以便向您展示一般原则。 But I'm sure you can see how to adapt this to your own situation:但我相信您可以看到如何根据您自己的情况进行调整:

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)

That's probably not the only way;这可能不是唯一的方法。 you could instead, I think, call NSCollectionLayoutGroup.custom and just lay out the cells manually.我认为,您可以改为调用NSCollectionLayoutGroup.custom并手动布置单元格。 But I think this is not a bad solution.但我认为这不是一个糟糕的解决方案。

I should also say that I'm not persuaded that a collection view is the best way to get the result you're trying to achieve.我还应该说,我不相信集合视图是获得您想要实现的结果的最佳方式。 You might do better just to lay out the seat views yourself, directly, in code.直接在代码中自己布置座位视图可能会更好。

I have the same problem while implementing my own keyboard.我在实现自己的键盘时遇到了同样的问题。 My result: Keyboard images .我的结果:键盘图像 This is how I did it without using constants (an improvement of Matt's awesome answer).这就是我在不使用常量的情况下做到的(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 represents the number of items per row count表示每行的项目数

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

containerWidth is the exact width of the view in CGFloat containerWidth是 CGFloat 中视图的确切宽度

let containerWidth = layoutEnvironment.container.contentSize.width

groupWidthDimension is the width of each group / keyboard tile including the applied insets groupWidthDimension是每个组/键盘图块的宽度,包括应用的插图

let groupWidthDimension = group.layoutSize.widthDimension.dimension

itemWidth gives you the exact size of each keyboard tile itemWidth为您提供每个键盘图块的确切大小

let itemWidth = containerWidth * groupWidthDimension

inset (leading) is calculated based on the difference of the containerWidth and the sum of all the items' width and then halved插入(前导)根据containerWidth和所有项目的宽度之和的差计算,然后减半

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

You could use NSCollectionLayoutGroup.custom(layoutSize:)<\/code> where we can set the frame using NSCollectionLayoutGroupCustomItemProvider<\/code> .您可以使用NSCollectionLayoutGroup.custom(layoutSize:)<\/code>我们可以使用NSCollectionLayoutGroupCustomItemProvider<\/code>设置框架。

Set the frame for each item using使用设置每个项目的框架

var customItems = [NSCollectionLayoutGroupCustomItem]()
            for item in 0..<itemCount {
                let frame = CGRect(x: yourCalculatedMargin, y: yPosition, width: layoutSize.widthDimension.dimension, height: layoutSize.heightDimension.dimension)
                customItems.append(NSCollectionLayoutGroupCustomItem(frame: frame))
            }
            return customItems

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM