【问题标题】:Swift 3: How to center horizontally the last row of cells in a UICollectionView with only one section?Swift 3:如何将 UICollectionView 中的最后一行单元格水平居中,只有一个部分?
【发布时间】:2016-12-11 21:10:03
【问题描述】:

我正在使用只有一个部分的UICollectionView。这是一些可视化:

[ x x x ]  
[ x x x ]  
[ x x   ] 

如果UICollectionView 中的最后一行没有填充所有 3 个单元格,我想像这样将这些单元格居中:

[ x x x ]  
[ x x x ]  
[  x x  ] 

我尝试从以下地方实施解决方案:

  1. How to center horizontally UICollectionView Cells?

  2. How to center align the cells of a UICollectionView?

但是,解决方案会移动所有单元格,如果最后一行不包含 X 个单元格,我只想移动最后一行,因为我只有一个部分。

我知道如何设置插图,但我不知道如何通过只有一个部分并尝试调整最后一行单元格的插图来实现这一点。

我刚开始使用UICollectionView,不知道如何解决这个问题?

【问题讨论】:

    标签: ios uicollectionview swift3 uicollectionviewcell


    【解决方案1】:

    听起来您需要流布局提供的所有内容,并进行一些自定义。子类化流布局和覆盖layoutAttributesForElements 应该可以完成这项工作:

    一个快速而肮脏的实现基本上会要求 FlowLayout 为给定的矩形进行布局,然后找出最后一行出现的项目。如果少于 3 个项目,则将它们均匀隔开。

    class LastRowCenteredLayout: UICollectionViewFlowLayout {
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
            guard var elementAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
            guard elementAttributes.count > 0 else { return elementAttributes }
    
            elementAttributes = elementAttributes.map { $0.copy() as! UICollectionViewLayoutAttributes }
    
            let minY = elementAttributes.last!.frame.minY
            let lastRowAttrs = elementAttributes.reversed().filter { $0.frame.minY == minY }
    
            guard lastRowAttrs.count < 3,
                    let first = elementAttributes.first,
                    let last = elementAttributes.last else {
                return elementAttributes
            }
    
            let horizontalPadding = rect.width - first.frame.minX - last.frame.maxX
            let horizontalShift = horizontalPadding / 2.0
    
            for attrs in lastRowAttrs {
                attrs.frame = attrs.frame.offsetBy(dx: horizontalShift, dy: 0)
            }
    
            return elementAttributes
        }
    }
    

    请注意,如果您计划动画插入/删除,您还应该覆盖 layoutAttributesForCellWithIndexPath: 并确保它返回一致的结果。

    Apple 在 FlowLayout 上有一个 guide,其中有一个专门用于子类化的部分。

    示例游乐场:

    https://gist.github.com/AnuragMishra/0a694dfa9be1a5eab9fc7368b69812ad

    【讨论】:

      【解决方案2】:

      简短的回答是:你不能,使用 Apple 提供的 UICollectionViewFlowLayout

      更长的答案是: 您将不得不创建一个客户 UICollectionViewLayout 子类并自己放置元素。首先通过this tutorial。然后,您应该更好地了解内部工作原理,以便能够创建自己的自定义布局。

      【讨论】:

        【解决方案3】:

        只需在最后添加一个空单元格,即全角,之前的单元格将居中

        【讨论】:

          【解决方案4】:

          强文本您可以在您的 collectionViewLayout 函数中进行这个简单的计算。

          func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
          
              //return itemSize
              let spaceBetweenCell :CGFloat = 0
              let screenWidth = UIScreen.main.bounds.size.width - CGFloat(2 * spaceBetweenCell)
              let totalSpace = spaceBetweenCell * 1.0
              if indexPath.row == categories.count-1 {
                // check if last cell is odd
                if categories.count % 2  == 1 {
                  return CGSize(width: screenWidth , height: (screenWidth-totalSpace)/4) // all Width and  same previous height
                }else {
                  return itemSize
                }
              }else{
                return itemSize
              }
            }
          

          【讨论】: