美文网首页
直播三之瀑布流

直播三之瀑布流

作者: 阿文灬 | 来源:发表于2017-09-25 20:44 被阅读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]?内部可能调用该方法。

    实现瀑布流

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

    • 确定上下左右的内缩距离,UICollectionViewFlowLayout自身提供了sectionInset
    • 确定列数与layoutAttributes的个数
    • 计算各个layoutAttributes的frame
    • 细节上:记住每一列的最高高度,下一个cell将添加在高度最小的那一列。考虑上拉刷新、下拉加载等情况,cell的数量会变
    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

    相关文章

      网友评论

          本文标题:直播三之瀑布流

          本文链接:https://www.haomeiwen.com/subject/xdhysxtx.html