【问题标题】:Vertical offset on a UICollectionView columnUICollectionView 列上的垂直偏移
【发布时间】:2018-05-09 09:16:55
【问题描述】:

右图是我想要实现的目标

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

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

注意:我所有的单元格大小都相同。

【问题讨论】:

标签: ios swift uicollectionview interface-builder


【解决方案1】:

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

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

  2. collectionViewContentSize:根据您的初始计算返回整个内容区域的整体大小

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

现在我们有相同大小的单元格,这很容易实现。

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

    // 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]
    }

你可以在课堂上找到gist

它是这样出现的:

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

希望对你有帮助!

【讨论】:

  • 令人印象深刻!真的很有帮助谢谢!!!请问如何缩小两列间距和行间距?
  • 您可以公开cellPadding 以调整填充。我相信使用协议和委托通常是最好的方法。
猜你喜欢
  • 1970-01-01
  • 2013-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多