直播三之瀑布流

2017-09-25  本文已影响0人  阿文灬
瀑布流.gif

UICollectionViewLayout

UICollectionViewLayout向UICollectionView提供布局信息,不仅包括cell的布局信息,也包括追加视图和装饰视图的布局信息。
实现一个自定义layout的常规做法是继承UICollectionViewLayout类。下面简单介绍与cell相关的三个重要方法(还有其他的)。
func prepare()
布局调用的第一个方法,如果collectionView重新加载时,也会再次调用。
必须实现父类的该方法。

func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
返回用于补充或装饰视图的布局属性,或以屏幕方式按需进行布局。
该方法调用比较多

func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
根据需要返回特定索引路径的布局属性实例。
官方文档说,该方法should implement。但是个人测试后觉得一般最好不实现的,并且该方法在系统内部不会被调用,只用于辅助自己实现的例如func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?内部可能调用该方法。

实现瀑布流

这里代码,并且带有代码非常简短,所以大概讲一下逻辑,直接贴出代码算了。

protocol LWWaterfallsFlowLayoutDataSource: class {
    func numberOfCols(in layout: LWWaterfallsFlowLayout) -> Int
    func waterfallsFlowLayout(_ layout: LWWaterfallsFlowLayout, heightAt item: Int) -> CGFloat
}

class LWWaterfallsFlowLayout: UICollectionViewFlowLayout {

    weak var dataSource: LWWaterfallsFlowLayoutDataSource?
    
    fileprivate lazy var attrArr = [UICollectionViewLayoutAttributes]()
    fileprivate lazy var cols : Int = {
        return self.dataSource?.numberOfCols(in: self) ?? 3
    }()
    fileprivate lazy var totalHeights : [CGFloat] = Array(repeating: self.sectionInset.top, count: self.cols)
    
    override func prepare() {
        super.prepare()
        
        print("prepare")
        
        let itemCount = collectionView!.numberOfItems(inSection: 0)
        
        let attrW : CGFloat = (collectionView!.bounds.width - sectionInset.left - sectionInset.right - CGFloat(cols - 1) * minimumInteritemSpacing) / CGFloat(cols)
        
        for item in attrArr.count..<itemCount {
            let attr = UICollectionViewLayoutAttributes(forCellWith: IndexPath(item: item, section: 0))
            
            guard let attrH : CGFloat = dataSource?.waterfallsFlowLayout(self, heightAt: item) else {
                fatalError("请实现对应的数据源方法,并且返回Cell高度")
            }
            let minH = totalHeights.min()!
            let minIndex = totalHeights.index(of: minH)!
            let attrX : CGFloat = sectionInset.left + (minimumInteritemSpacing + attrW) * CGFloat(minIndex)
            let attrY : CGFloat = minH
            
            attr.frame = CGRect(x: attrX, y: attrY, width: attrW, height: attrH)
            
            attrArr.append(attr)
            totalHeights[minIndex] = minH + minimumLineSpacing + attrH
        }
    }

    // 在这里该方法不会被调用
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        print("layoutAttributesForItem")
        return attrArr[indexPath.item]
    }
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        print("layoutAttributesForElements")
        return attrArr
    }
    
    override var collectionViewContentSize: CGSize {
        return CGSize(width: 0, height: totalHeights.max()! + sectionInset.bottom - minimumLineSpacing)
    }
    
}

github:https://github.com/taoGod/IM-MG3

上一篇 下一篇

猜你喜欢

热点阅读