UICollectionView 列的垂直偏移

Vertical offset on a UICollectionView column

右图是我努力实现的

有谁知道我如何在两列 UICollectionView 上实现这一点? 我可以通过测试 if (indexPath.row % 2 = 0) 来辨别我的专栏,但我无法设法实现这个结果。

这是一种简单的方法吗?或者我需要自定义 UICollectionViewFlowLayout 吗?

注意:我所有的单元格大小都一样。

是的,您需要创建自定义 UICollectionViewLayout,这很容易实现。您只需要以下内容:

  1. prepare():执行提供布局信息所需的前期计算

  2. collectionViewContentSize: Return 整个内容区域的总体大小基于您的初步计算

  3. layoutAttributesForElements(in:): Return 指定矩形中的单元格和视图的属性

既然我们有相同大小的单元格,就很容易实现了。

让我们声明几个要使用的变量:

    // Adjust this as you need
    fileprivate var offset: CGFloat = 50

    //    Properties for configuring the layout: the number of columns and the cell padding.
    fileprivate var numberOfColumns = 2
    fileprivate var cellPadding: CGFloat = 10

    //    Cache the calculated attributes. When you call prepare(), you’ll calculate the attributes for all items and add them to the cache. You can be efficient and 
    fileprivate var cache = [UICollectionViewLayoutAttributes]()

    //    Properties to store the content size.
    fileprivate var contentHeight: CGFloat = 0
    fileprivate var contentWidth: CGFloat {
        guard let collectionView = collectionView else {
            return 0
        }
        let insets = collectionView.contentInset
        return collectionView.bounds.width - (insets.left + insets.right)
    }

接下来让我们覆盖 prepare() 方法

    override func prepare() {
        // If cache is empty and the collection view exists – calculate the layout attributes
        guard cache.isEmpty == true, let collectionView = collectionView else {
            return
        }

        // xOffset: array with the x-coordinate for every column based on the column widths
        // yOffset: array with the y-position for every column, Using odd-even logic to push the even cell upwards and odd cells down.
        let columnWidth = contentWidth / CGFloat(numberOfColumns)
        var xOffset = [CGFloat]()
        for column in 0 ..< numberOfColumns {
            xOffset.append(CGFloat(column) * columnWidth)
        }
        var column = 0

        var yOffset = [CGFloat]()
        for i in 0..<numberOfColumns {
            yOffset.append((i % 2 == 0) ? 0 : offset)
        }

        for item in 0 ..< collectionView.numberOfItems(inSection: 0) {

            let indexPath = IndexPath(item: item, section: 0)

            // Calculate insetFrame that can be set to the attribute
            let cellHeight = columnWidth - (cellPadding * 2)
            let height = cellPadding * 2 + cellHeight
            let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
            let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)

            // Create an instance of UICollectionViewLayoutAttribute, sets its frame using insetFrame and appends the attributes to cache.
            let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
            attributes.frame = insetFrame
            cache.append(attributes)

            // Update the contentHeight to account for the frame of the newly calculated item. It then advances the yOffset for the current column based on the frame
            contentHeight = max(contentHeight, frame.maxY)
            yOffset[column] = yOffset[column] + height

            column = column < (numberOfColumns - 1) ? (column + 1) : 0
        }
    }

最后我们需要 collectionViewContentSizelayoutAttributesForElements(in:)

    //    Using contentWidth and contentHeight from previous steps, calculate collectionViewContentSize.
    override var collectionViewContentSize: CGSize {
        return CGSize(width: contentWidth, height: contentHeight)
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

        var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()

        for attributes in cache {
            if attributes.frame.intersects(rect) {
                visibleLayoutAttributes.append(attributes)
            }
        }
        return visibleLayoutAttributes
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return cache[indexPath.item]
    }

您可以通过 class.

找到 gist

它是这样显示的:

注意:这只是一个演示,您可能需要根据需要进行调整。

希望对您有所帮助!