如何水平居中UICollectionView细胞?

Rap*_*toX 107 ios swift

我做了一些研究,但是我找不到任何关于如何在UICollectionView中水平居中单元格的代码示例.

而不是第一个单元格像这个X00,我希望它像这个0X0.有没有办法实现这个目标?

编辑:

想象我想要的东西:

在此输入图像描述

当CollectionView中只有一个元素时,我需要它看起来像版本B. 当我有多个元素时,它应该像版本A但有更多元素.

当我只有1个元素时,它看起来像版本A,我想知道我怎么能让它看起来像B.

谢谢您的帮助!

Dar*_*el. 199

使用库不是一个好主意,如果你的目的只是这个,即中心对齐.

更好的是,您可以在collectionViewLayout函数中执行此简单计算.

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

    let totalCellWidth = CellWidth * CellCount
    let totalSpacingWidth = CellSpacing * (CellCount - 1)

    let leftInset = (collectionViewWidth - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
Run Code Online (Sandbox Code Playgroud)

  • 在Swift 3中,新方法签名是`collectionView(_ collectionView:UICollectionView,layout collectionViewLayout:UICollectionViewLayout,insetForSectionAt section:Int)`. (5认同)
  • @DarshanPatel。感谢很多答案,我实现了这一点,并且行应该居中,但现在问题是我无法滚动到第一项。当我尝试滚动到第一项时,它会将我带回到修改后的 UIEdgeInsets。你可以看到我的演示应用 https://github.com/anirudha-music/CollectionViewCenter (4认同)
  • @DarshanPatel。您的答案有时会在较小的设备上产生负值。考虑像这样对您的leftInset值使用最大值检查:let let LeftInset = max(0.0,(self.collectionView.bounds.width-CGFloat(totalCellWidth + totalSpacingWidth))/ 2)` (4认同)
  • 这应该是公认的答案,因为它清晰简洁并解释了逻辑. (2认同)
  • 你怎么能抓住cellWidth,是否可以通过cellForItemAt方法?我试过了,它返回 nil .. 单元格宽度根据屏幕尺寸而变化.. @DarshanPatel。 (2认同)
  • @Chris @Balanced 将“UICollectionViewLayout”转换为“UICollectionViewFlowLayout”,并使用“itemSize”属性来获取单元格宽度。 (2认同)
  • 如果您不是子类化UICollectionViewController,请确保您的类符合UICollectionViewDelegateFlowLayout,否则它将无法正常工作 (2认同)

Ahm*_*adi 46

Swift 4.2

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

    let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
    let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

    let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
    let rightInset = leftInset

    return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)

}
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

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

        let totalCellWidth = 80 * collectionView.numberOfItems(inSection: 0)
        let totalSpacingWidth = 10 * (collectionView.numberOfItems(inSection: 0) - 1)

        let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
        let rightInset = leftInset

        return UIEdgeInsetsMake(0, leftInset, 0, rightInset)

    }
Run Code Online (Sandbox Code Playgroud)

不要忘记添加协议

UICollectionViewDelegateFlowLayout
Run Code Online (Sandbox Code Playgroud)

  • 当有适合 collectionView 的单元格时,当单元格计数增加时,您的答案工作正常,单元格位于中心,并且您无法滚动到第一个单元格或最后一个单元格。 (2认同)
  • @Vitalii 80 表示单元格宽度,10 表示单元格之间的空间,如果您阅读变量名称,您就会明白它的含义:P (2认同)

osc*_*lon 22

试试这个Swift 4吧

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        let cellWidth : CGFloat = 165.0

        let numberOfCells = floor(self.view.frame.size.width / cellWidth)
        let edgeInsets = (self.view.frame.size.width - (numberOfCells * cellWidth)) / (numberOfCells + 1)

        return UIEdgeInsetsMake(15, edgeInsets, 0, edgeInsets)
    }
Run Code Online (Sandbox Code Playgroud)

添加您的cellWidth而不是165.0

  • 这是最好的答案。用最简单的数学计算进去。适用于任意数量的行和列 (3认同)

Two*_*aws 19

我使用KTCenterFlowLayout来做这件事,效果很好.它是一个自定义子类,UICollectionViewFlowLayout可以根据需要使单元格居中.(注意:通过发布一些代码来解决这个问题并非易事,这就是为什么我要链接到GitHub项目!)

  • 无法通过 IB 使其发挥作用。[这个库](https://github.com/Coeur/CollectionViewCenteredFlowLayout) 对我来说就像一个魅力。刚刚安装了 Pod,并更改了 IB 中的布局类别! (2认同)

Stu*_*ner 13

Darshan Patel的客观C版答案:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    CGFloat totalCellWidth = kItemWidth * self.dataArray.count;
    CGFloat totalSpacingWidth = kSpacing * (((float)self.dataArray.count - 1) < 0 ? 0 :self.dataArray.count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*isu 9

流程布局的通用解决方案,如果页面小于宽度,则将页面居中;如果页面更多,则向左对齐

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(nonnull UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    // Centering if there are fever pages
    CGSize itemSize = [(UICollectionViewFlowLayout *)collectionViewLayout itemSize];
    CGFloat spacing = [(UICollectionViewFlowLayout *)collectionViewLayout minimumLineSpacing];

    NSInteger count = [self collectionView:self numberOfItemsInSection:section];
    CGFloat totalCellWidth = itemSize.width * count;
    CGFloat totalSpacingWidth = spacing * ((count - 1) < 0 ? 0 : count - 1);
    CGFloat leftInset = (self.bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2;
    if (leftInset < 0) {
        UIEdgeInsets inset = [(UICollectionViewFlowLayout *)collectionViewLayout sectionInset];
        return inset;
    }
    CGFloat rightInset = leftInset;
    UIEdgeInsets sectionInset = UIEdgeInsetsMake(0, leftInset, 0, rightInset);
    return sectionInset;
}
Run Code Online (Sandbox Code Playgroud)

Swift 版本(从 ObjC 转换而来)

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    // Centering if there are fever pages
    let itemSize: CGSize? = (collectionViewLayout as? UICollectionViewFlowLayout)?.itemSize
    let spacing: CGFloat? = (collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing

    let count: Int = self.collectionView(self, numberOfItemsInSection: section)
    let totalCellWidth = (itemSize?.width ?? 0.0) * CGFloat(count)
    let totalSpacingWidth = (spacing ?? 0.0) * CGFloat(((count - 1) < 0 ? 0 : count - 1))
    let leftInset: CGFloat = (bounds.size.width - (totalCellWidth + totalSpacingWidth)) / 2
    if leftInset < 0 {
        let inset: UIEdgeInsets? = (collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset
        return inset!
    }
    let rightInset: CGFloat = leftInset
    let sectionInset = UIEdgeInsets(top: 0, left: Float(leftInset), bottom: 0, right: Float(rightInset))
    return sectionInset
}
Run Code Online (Sandbox Code Playgroud)

无标题-3.png


S. *_*ura 7

您可以使用此扩展程序 (Swift 4)。

如果您collectionViewlayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize.

它适用于任何细胞大小,并且在以下情况下完美运行 scrollDirection = .horizontal

public extension UICollectionView {
    func centerContentHorizontalyByInsetIfNeeded(minimumInset: UIEdgeInsets) {
        guard let layout = collectionViewLayout as? UICollectionViewFlowLayout,
            layout.scrollDirection == .horizontal else {
                assertionFailure("\(#function): layout.scrollDirection != .horizontal")
                return
        }

        if layout.collectionViewContentSize.width > frame.size.width {
            contentInset = minimumInset
        } else {
            contentInset = UIEdgeInsets(top: minimumInset.top,
                                        left: (frame.size.width - layout.collectionViewContentSize.width) / 2,
                                        bottom: minimumInset.bottom,
                                        right: 0)
        }
    }
}


final class Foo: UIViewController {
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.centerContentHorizontalyByInsetIfNeeded(minimumInset: yourDefaultInset)
    }
}
Run Code Online (Sandbox Code Playgroud)

希望对你有帮助!


MXV*_*MXV 6

略微修改@Safad Funy的答案,这对于Swift和iOS的最新版本对我来说是有用的。在这种情况下,我希望单元格的宽度为集合视图大小的三分之一。

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

  let totalCellWidth = Int(collectionView.layer.frame.size.width) / 3 * collectionView.numberOfItems(inSection: 0)
  let totalSpacingWidth = (collectionView.numberOfItems(inSection: 0) - 1)

  let leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
  let rightInset = leftInset

  return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
Run Code Online (Sandbox Code Playgroud)

  • 当只有一个细胞时,这对我尤其有效。 (3认同)

小智 5

Swift 4.2(水平和垂直)。这是粉红豹代码的小升级,非常感谢他!


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

        print(edgeInsetWidth, edgeInsetWidth)
        return UIEdgeInsets(top: 5, left: edgeInsetWidth, bottom: flowLayout.sectionInset.top, right: edgeInsetWidth)
    } else {
        let edgeInsetHieght = (collectionHeight - totalHieght) / 2
        print(edgeInsetHieght, edgeInsetHieght)
        return UIEdgeInsets(top: edgeInsetHieght, left: flowLayout.sectionInset.top, bottom: edgeInsetHieght, right: flowLayout.sectionInset.top)

    }
}
Run Code Online (Sandbox Code Playgroud)

确保您的类符合UICollectionViewDelegateFlowLayout协议


Sae*_* Ir 5

这是Swift 5的较新版本,当单元格多于一行时,它也能正常工作:

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
    var cellCount = CGFloat(collectionView.numberOfItems(inSection: section))
    var collectionWidth = collectionView.frame.size.width
    var totalWidth: CGFloat
    if #available(iOS 11.0, *) {
        collectionWidth -= collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right
    }
    repeat {
        totalWidth = cellWidth * cellCount + cellSpacing * (cellCount - 1)
        cellCount -= 1
    } while totalWidth >= collectionWidth

    if (totalWidth > 0) {
        let edgeInset = (collectionWidth - totalWidth) / 2
        return UIEdgeInsets.init(top: flowLayout.sectionInset.top, left: edgeInset, bottom: flowLayout.sectionInset.bottom, right: edgeInset)
    } else {
        return flowLayout.sectionInset
    }
}
Run Code Online (Sandbox Code Playgroud)

请确保你的类符合UICollectionViewDelegateFlowLayout协议。