Swift 3:如何将 UICollectionView 中的最后一行单元格水平居中,只有一个部分?

Posted

技术标签:

【中文标题】Swift 3:如何将 UICollectionView 中的最后一行单元格水平居中,只有一个部分?【英文标题】:Swift 3: How to center horizontally the last row of cells in a UICollectionView with only one section? 【发布时间】: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  ] 

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

    How to center horizontally UICollectionView Cells?

    How to center align the cells of a UICollectionView?

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

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

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

【问题讨论】:

【参考方案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
    
  

【讨论】:

以上是关于Swift 3:如何将 UICollectionView 中的最后一行单元格水平居中,只有一个部分?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用部分在CollectionView中水平居中行

在 Swift 中以编程方式在 UITableViewCell 中创建一个 UICollectionView

swift 如何将Swift 3内置的cocoapod更新为Swift 4

如何将 UIStepper 保存到 CoreData (swift 3)

如何将图片分配给 UIImageView (Swift 3)

如何将完整的 UserDefaults 列表放入 tableview - Swift 3