【问题标题】:How to center align the cells of a UICollectionView in Swift3.0?如何在 Swift3.0 中居中对齐 UICollectionView 的单元格?
【发布时间】:2016-11-14 09:48:52
【问题描述】:

说明:

Objective-CSwift2.0 的答案:How to center align the cells of a UICollectionView?

我通常会尝试将Swift2.0 答案转换为Swift3.0 解决方案,但是方法:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
        let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
        return UIEdgeInsetsMake(0, edgeInsets, 0, 0);
    }

Swift3.0 中似乎不存在,我发现唯一有用的其他方法是:

func collectionView(_ collectionView: UICollectionView, transitionLayoutForOldLayout fromLayout: UICollectionViewLayout, newLayout toLayout: UICollectionViewLayout) -> UICollectionViewTransitionLayout {
        <#code#>
}

但我不确定如何正确实施。

问题:

如何在Swift3.0 中将UICollectionView 的单元格居中对齐?

(iOS 和 tvOS 的简单通用解决方案将是完美的)

【问题讨论】:

标签: ios swift swift3 tvos


【解决方案1】:

这最终成为我使用的解决方案。阅读代码 cmets 以获得更好的理解。 斯威夫特 5

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    //Where elements_count is the count of all your items in that
    //Collection view...
    let cellCount = CGFloat(elements_count)

    //If the cell count is zero, there is no point in calculating anything.
    if cellCount > 0 {
        let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
        let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing

        //20.00 was just extra spacing I wanted to add to my cell.
        let totalCellWidth = cellWidth*cellCount + 20.00 * (cellCount-1)
        let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right

        if (totalCellWidth < contentWidth) {
            //If the number of cells that exists take up less room than the
            //collection view width... then there is an actual point to centering them.

            //Calculate the right amount of padding to center the cells.
            let padding = (contentWidth - totalCellWidth) / 2.0
            return UIEdgeInsets(top: 0, left: padding, bottom: 0, right: padding)
        } else {
            //Pretty much if the number of cells that exist take up
            //more room than the actual collectionView width, there is no
            // point in trying to center them. So we leave the default behavior.
            return UIEdgeInsets(top: 0, left: 40, bottom: 0, right: 40)
        }
    }
    return UIEdgeInsets.zero
}

【讨论】:

  • 我解决了这正是(swift 4),编译,但单元格不在屏幕上居中?
  • @AlexKornhauser 它明确声明它适用于 Swift 3.0。这是公认的答案,因为它对我来说非常好。接受的答案不一定是“最佳”答案,只要答案是 OP 的问题。由于我是 OP,我显然选择了对我有用的东西。随意尝试jbouaziz 更新版本。赞成票更好地找到“最佳”答案。干杯。
  • 可以这样获取cellCount值:let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
【解决方案2】:

虽然rottenoats 的答案很棒,但它有一个额外的间距错误,并且没有使用很多可用的 swift 3 语法。我已经解决了这个问题并减少了对局部变量的依赖数量。

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {

    // Make sure that the number of items is worth the computing effort.
    guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout,
        let dataSourceCount = collectionView.dataSource?.collectionView(collectionView, numberOfItemsInSection: section),
        dataSourceCount > 0 else {
            return .zero
    }


    let cellCount = CGFloat(dataSourceCount)
    let itemSpacing = flowLayout.minimumInteritemSpacing
    let cellWidth = flowLayout.itemSize.width + itemSpacing
    var insets = flowLayout.sectionInset


    // Make sure to remove the last item spacing or it will
    // miscalculate the actual total width.
    let totalCellWidth = (cellWidth * cellCount) - itemSpacing
    let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right


    // If the number of cells that exist take up less room than the
    // collection view width, then center the content with the appropriate insets.
    // Otherwise return the default layout inset.
    guard totalCellWidth < contentWidth else {
        return insets
    }


    // Calculate the right amount of padding to center the cells.
    let padding = (contentWidth - totalCellWidth) / 2.0
    insets.left = padding
    insets.right = padding
    return insets
}

注意:此 sn-p 仅适用于水平滚动,但可以轻松调整。

【讨论】:

    【解决方案3】:

    对@rottenoats 答案的轻微改编。这个比较通用。

    最重要的是记住让你的视图控制器符合 UICollectionViewDelegateFlowLayout 协议。

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    
        guard let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout else {
            return .zero
        }
    
        let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    
        if cellCount > 0 {
            let cellWidth = flowLayout.itemSize.width + flowLayout.minimumInteritemSpacing
    
            let totalCellWidth = cellWidth * cellCount
            let contentWidth = collectionView.frame.size.width - collectionView.contentInset.left - collectionView.contentInset.right - flowLayout.headerReferenceSize.width - flowLayout.footerReferenceSize.width
    
            if (totalCellWidth < contentWidth) {
                let padding = (contentWidth - totalCellWidth + flowLayout.minimumInteritemSpacing) / 2.0
                return UIEdgeInsetsMake(0, padding, 0, 0)
            }
        }
    
        return .zero
    }
    

    【讨论】:

    • 最佳答案!非常感谢!
    【解决方案4】:

    这是一个最近的解决方案,适用于 Swift 5.0

    extension YourViewController: UICollectionViewDelegateFlowLayout {
        func collectionView(_ collectionView: UICollectionView,
                            layout collectionViewLayout: UICollectionViewLayout,
                            insetForSectionAt section: Int) -> UIEdgeInsets {
            let itemWidth = 80
            let spacingWidth = 4
            let numberOfItems = collectionView.numberOfItems(inSection: section)
            let cellSpacingWidth = numberOfItem * spacingWidth
            let totalCellWidth = numberOfItems * itemWidth + cellSpacingWidth
            let inset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth)) / 2
            return UIEdgeInsets(top: 5, left: inset, bottom: 5, right: inset)
        }
    }
    

    【讨论】:

      【解决方案5】:

      您正在寻找的方法在Swift 3 中具有不同的签名。新签名是这样的:

      optional public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
      

      PS:此方法存在于UICollectionViewDelegateFlowLayout 协议中。
      希望这会有所帮助。

      【讨论】:

        【解决方案6】:

        假设你符合UICollectionViewDelegateFlowLayout,应该是:

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
            let edgeInsets = (screenWight - (CGFloat(elements.count) * 50) - (CGFloat(elements.count) * 10)) / 2
            return UIEdgeInsets(top: 0, left: edgeInsets, bottom: 0, right: 0)
        }
        

        【讨论】:

          【解决方案7】:
          func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
          
          let allCellWidth = KcellWidth * numberOfCell
          let cellSpacingWidth = CellSpacing * (numberOfCell - 1)
          
          let leftInset = (collectionViewWidth - CGFloat(allCellWidth + cellSpacingWidth)) / 2
          let rightInset = leftInset
          
          return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
          }
          

          【讨论】:

            【解决方案8】:

            此代码应水平居中任何类型的集合视图,即使在 Swift 4.0 中有额外项目:

            func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
                let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
                let cellWidth: CGFloat = flowLayout.itemSize.width
                let cellSpacing: CGFloat = flowLayout.minimumInteritemSpacing
                let cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
                var collectionWidth = collectionView.frame.size.width
                if #available(iOS 11.0, *) {
                    collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
                }
                let totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
                if totalWidth <= collectionWidth {
                    let edgeInset = (collectionWidth - totalWidth) / 2
                    return UIEdgeInsetsMake(flowLayout.sectionInset.top, edgeInset, flowLayout.sectionInset.bottom, edgeInset)
                } else {
                    return flowLayout.sectionInset
                }
            }
            

            不要忘记,如果你没有继承 UICollectionViewController,请确保你的类符合 UICollectionViewDelegateFlowLayout 协议

            【讨论】:

              【解决方案9】:

              您需要符合UICollectionViewDelegateFlowLayout 协议才能找到collectionView(_:layout:insetForSectionAt:) 方法,它在那里定义。以下实现在 swift 4 中适用于水平 collectionView

              extension YourViewController: UICollectionViewDelegateFlowLayout {
                  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
                      let cellWidth = CGFloat(integerLiteral: YourCellsWidth)
                      let count = self.YourCollectionViewDataSource.count
                      let top = CGFloat(integerLiteral: 0)    // I don't need to set top and bottom spacing
                      let cellsAccumulatedWidth = CGFloat(integerLiteral: count) * cellWidth
                      let cellsSpacingAccumulatedWidth = CGFloat(integerLiteral: (count - 1) * 5)
                      let left = (self.collectionView.frame.size.width - cellsAccumulatedWidth - cellsSpacingAccumulatedWidth) / 2
                      let bottom = top
                      let right = left
              
                      return UIEdgeInsetsMake(top, left, bottom, right);
                  }
              }
              

              【讨论】:

                【解决方案10】:

                将此解决方案用于居中对齐的水平滚动。

                let totalCellWidth = Int(collectionView.frame.height * CGFloat(numberOfItems()))
                
                        // if total width is greater than collection's width, then no need to align center
                        if totalCellWidth > Int(collectionView.frame.width) {
                            return UIEdgeInsets.zero
                        }
                
                        let totalSpacingWidth = cellSpacing * (numberOfItems() - 1)
                        let leftInset = (collectionView.frame.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
                        let rightInset = leftInset
                        return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
                

                【讨论】:

                  【解决方案11】:

                  如果您的 collectionView 有一行,我认为最简单的解决方案是用滚动视图中的 stackView 替换它,这样您就可以设置视图之间的间距。 此外,如果你想要一些填充,你可以应用它。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-04-27
                    • 1970-01-01
                    • 2019-08-04
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多