瀑布流

效果图如下:


瀑布流_第1张图片

1、自定义瀑布流布局

要想实现collectionView的任意格式的瀑布流布局,需要自定义布局

下面的方法是在自定义LGWaterfullLayout中实现的

 // 通过数据源协议,获取外部传过来的高度
protocol LGWaterfullLayoutDataSource: class {
    func waterfullLayout(_ layout: UICollectionViewFlowLayout, itemIndex: Int) -> CGFloat
}

class LGWaterfullLayout: UICollectionViewFlowLayout {
    // 暴露接口给外面,列数,默认为3
    var cols = 3
    // 数据源协议,用于接收外面传过来的cell高度
    weak var dataSource : LGWaterfullLayoutDataSource?
    
    // 布局最重要的部分,attributes保存所有cell的frame
    fileprivate lazy var attributes : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()
    
    // 设置collectionView默认的ContentSize高度
    fileprivate lazy var maxHeight : CGFloat = self.sectionInset.top + self.sectionInset.bottom
    
    // 保存collectionView每一列的总高度,因为下一个cell总是放在当前高度最低的地方
    fileprivate lazy var heights : [CGFloat] = Array(repeating: self.sectionInset.top, count: self.cols)
}

2.准备cell的布局

override func prepare() {
        
        // 1.校验collectionView有没有值
        guard let collectionView = collectionView else {
            return
        }
        
        // 2.获取cell的个数,此处只有一个section
        let count = collectionView.numberOfItems(inSection: 0)
        
        // 3.遍历所有的cell,给每一个cell准备一个UICollectionViewLayoutAttributes
        // 获取cell的宽度,此宽度为固定的
        let itemW = (collectionView.bounds.width - sectionInset.left - sectionInset.right - (CGFloat(cols) - 1) * minimumInteritemSpacing) / CGFloat(cols)
        
        // 遍历所有cell,每次都从新加载的开始布局,之前布局过的跳过,此处主要是为了上拉加载更多的需要
        for i in attributes.count..

3.获取准备好的布局

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return attributes
    }

4.获取滚动的范围

override var collectionViewContentSize: CGSize {
        return CGSize(width: 0, height: maxHeight)
    }

5、在ViewController里创建collectionView瀑布流

下面内容在ViewController里实现
1、创建collectionView,并设置参数、代理和数据源

 fileprivate lazy var collectionView : UICollectionView = {
        let layout : LGWaterfullLayout = LGWaterfullLayout()
        // 设置行间距
        layout.minimumLineSpacing  = 10
        // 设置列间距
        layout.minimumInteritemSpacing = 10
        // 设置collectionView距离上下左右的间距
        layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10)
        // 设置列数
        layout.cols = 3
        // 设置layout的数据源
        layout.dataSource = self
        
        let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height - 64), collectionViewLayout: layout)
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.backgroundColor = UIColor.white
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellID)
        return collectionView
        
    }()

2、实现UICollectionViewDataSource数据源

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return itemCount
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath)
        
        cell.backgroundColor = UIColor.randomColor()
        var label: UILabel? = cell.contentView.subviews.first as? UILabel
        if label == nil {
            label = UILabel(frame: cell.bounds)
            label?.textAlignment = .center
            cell.contentView.addSubview(label!)
        }
        label?.text = "\(indexPath.item)"
        return cell
    }

3、 实现上拉加载更多

 // 上拉加载更多
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        if scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.bounds.height {
            itemCount += 30
            collectionView.reloadData()
        }
    }

4、实现LGWaterfullLayoutDataSource数据源协议,返回cell的高度

func waterfullLayout(_ layout: UICollectionViewFlowLayout, itemIndex: Int) -> CGFloat {
        return CGFloat(arc4random_uniform(150) + 100)        
    }

你可能感兴趣的:(瀑布流)