UICollectionView 列上的垂直偏移 [英] Vertical offset on a UICollectionView column

查看:30
本文介绍了UICollectionView 列上的垂直偏移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

右边的图片是我试图实现的

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

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

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

解决方案

是的,您需要创建一个自定义的 UICollectionViewLayout 并且实现起来很简单.您只需要以下内容:

  1. 注意:这只是一个演示,您可能需要根据自己的需要进行调整.

    希望有帮助!

    Image on right is what I try to achieve

    Does anyone know how I could achieve this on a two column UICollectionView ? I'm able to discern my columns by testing if (indexPath.row % 2 = 0) but I can't manage to achieve this result.

    Is their a simple way to do so ? Or would I need a custom UICollectionViewFlowLayout ?

    Note : All my cells are the same size.

    解决方案

    Yes, you need to create a custom UICollectionViewLayout and that's simple to achieve. All you need is the following:

    1. prepare(): Perform the up-front calculations needed to provide layout information

    2. collectionViewContentSize: Return the overall size of the entire content area based on your initial calculations

    3. layoutAttributesForElements(in:): Return the attributes for cells and views that are in the specified rectangle

    Now that we have cells of the same size it's pretty easy to achieve.

    Let's declare few variables to use:

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

    Next let's override the prepare() method

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

    Last we need collectionViewContentSize and layoutAttributesForElements(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]
        }
    

    You can find gist with the class.

    This is how it appears:

    Note: It is just a demo, you may have to tweak it according to your needs.

    Hope It Helps!

    这篇关于UICollectionView 列上的垂直偏移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆