UICollectionView列上的垂直偏移量

时间:2017-11-25 17:41:06

标签: ios swift uicollectionview interface-builder

右边的图像是我试图实现的目标

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

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

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

1 个答案:

答案 0 :(得分:0)

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

  1. prepare():执行提供布局信息所需的前期计算
  2. collectionViewContentSize:根据您的初始计算返回整个内容区域的整体尺寸

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

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

    让我们声明一些变量:

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

    出现的方式如下:

    Demo

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

    希望它有帮助!