自定义瀑布流LFWaterFallLayout

2020-09-18  本文已影响0人  菲特峰

瀑布流布局网上有很多demo,我只是使用swift重写一遍而已,原理很简单,重写UICollectionViewLayout布局

//
//  LFWaterFallLayout.swift
//  PXSTrain
//
//  Created by Pro on 2020/9/17.
//  Copyright © 2020 com.liufeng.mysterFeng. All rights reserved.
//

import UIKit
let LFDefaultColunmCount:Int = 3
let LFDefaultColunmMargin:CGFloat = 10.0
let LFDefaultRowMargin:CGFloat = 10.0
let LFDefaultEdgeInsets:UIEdgeInsets = UIEdgeInsets.init(top: 10, left: 10, bottom: 10, right: 10)



 @objc protocol LFWaterFallLayoutDelegate {
    //每个item的高度
    @objc func heightForItemAtIndexPath(indexPath:Int,itemWidth:CGFloat,waterFallLayout:LFWaterFallLayout) -> CGFloat
    //多少列
    @objc optional func columnCountInWaterFallLayout(waterFallLayout:LFWaterFallLayout) -> Int
    //列间距
    @objc optional func columnMarginInWaterFallLayout(waterFallLayout:LFWaterFallLayout) -> CGFloat
    //行间距
    @objc optional func rowMarginInWaterFallLayout(waterFallLayout:LFWaterFallLayout) -> CGFloat
    // 每个item的内边距
    @objc optional func edgeInsetdInWaterFallLayout(waterFallLayout:LFWaterFallLayout) -> UIEdgeInsets

}

class LFWaterFallLayout: UICollectionViewLayout {
    weak var delegate:LFWaterFallLayoutDelegate?
    //存放所有布局属性
    var attrsArr = Array<Any>()
    //存放所有列的当前高度
    var columnHeights = [CGFloat]()
    //内容的高度
    var contentHeight:CGFloat = 0
    
    var colunmCount:Int {
        get {
            return self.delegate?.columnCountInWaterFallLayout?(waterFallLayout: self) ?? LFDefaultColunmCount
        }
    }
    
    var columnMargin:CGFloat {
        get {
            return self.delegate?.columnMarginInWaterFallLayout?(waterFallLayout: self) ?? LFDefaultColunmMargin
        }
        
    }
    var rowMargin:CGFloat {
          get {
            return self.delegate?.rowMarginInWaterFallLayout?(waterFallLayout: self) ?? LFDefaultRowMargin
          }
          
      }
    var edgeInsets:UIEdgeInsets {
        get {
            return self.delegate?.edgeInsetdInWaterFallLayout?(waterFallLayout: self) ?? LFDefaultEdgeInsets
        }
    }
    
    override func prepare() {
        super.prepare()
        contentHeight = 0
        //清楚所有计算的高度
        columnHeights.removeAll()
        //设置每一列默认高度
        for _ in 0..<LFDefaultColunmCount {
            columnHeights.append(LFDefaultEdgeInsets.top)
        }
        //清除之前所有布局属性
        attrsArr.removeAll()
        
        //开始创建每一个cell对应的布局属性
        let count:Int = self.collectionView?.numberOfItems(inSection: 0) ?? 0
        
        for i in 0 ..< count {
            let indexPath = IndexPath.init(item: i, section: 0)
            let attrs:UICollectionViewLayoutAttributes = self.layoutAttributesForItem(at: indexPath) ?? UICollectionViewLayoutAttributes.init()
            self.attrsArr.append(attrs)
        }
    }
    
    //返回对应index 位置cell的布局属性
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        //创建布局属性
        let attrs = UICollectionViewLayoutAttributes.init(forCellWith: indexPath)
        //collectionView的宽度
        let collectionViewW:CGFloat = self.collectionView?.frame.size.width ?? 0


        // 设置布局属性的frame
        
        let cellW:CGFloat = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.colunmCount-1).cgFloat * self.columnMargin) / self.colunmCount.cgFloat

        let cellH = self.delegate?.heightForItemAtIndexPath(indexPath: indexPath.item, itemWidth: cellW, waterFallLayout: self)
        
        //找最短的那一列
        var destColumn = 0
        var minColumnHeight = self.columnHeights[0]
        for i in 0..<LFDefaultColunmCount {
            let columnHeight = self.columnHeights[i]
            if minColumnHeight > columnHeight {
                minColumnHeight = columnHeight
                destColumn = i
            }
        }
        let cellX = self.edgeInsets.left + destColumn.cgFloat * (cellW + self.columnMargin)
        var cellY = minColumnHeight
        
        if cellY != self.edgeInsets.top {
            cellY += self.rowMargin
        }
        attrs.frame = CGRect.init(x: cellX, y: cellY, width: cellW, height: cellH ?? 0)
        // 更新最短那一列的高度
        self.columnHeights[destColumn] = attrs.frame.origin.y + attrs.frame.size.height
        // 记录内容的高度 - 即最长那一列的高度
        let  maxColumnHeight = self.columnHeights[destColumn]
        if self.contentHeight < maxColumnHeight {
            self.contentHeight = maxColumnHeight
        }
        
        return attrs
    }
    
//    * 决定cell的高度
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return self.attrsArr as? [UICollectionViewLayoutAttributes]
    }
    
//    * 内容的高度
     
    override var collectionViewContentSize: CGSize {
        get {
            return CGSize.init(width: 0, height: self.contentHeight+self.edgeInsets.bottom)
        }
    }


}

上一篇下一篇

猜你喜欢

热点阅读