美文网首页
swift 布瀑流布局layout,含headerview,fo

swift 布瀑流布局layout,含headerview,fo

作者: 授之以渔不如授之以鱼 | 来源:发表于2021-02-20 18:12 被阅读0次
效果如图 WechatIMG311.jpeg

话不多说,来码
一、HomeWaterFallsCollectionLayout:


import UIKit

protocol PinterestLayoutDelegate: AnyObject {
    
    func collectionView(_ collectionView: UICollectionView, calculateHeightAtIndexPath indexPath: IndexPath) -> CGFloat
    
    /// header高度(默认为0)
    func referenceSizeForHeader(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize
    
    /// footer高度(默认为0)
    func referenceSizeForFooter(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize
    
}

class HomeWaterFallsCollectionLayout: UICollectionViewFlowLayout{

    var isExpand: Bool = false
    
    weak var delegate: PinterestLayoutDelegate?
    
    //默认列数
    private(set) var ColumnCountDefault: Int = 2
    //垂直间隔
    private(set) var lineSpacing: CGFloat = 16.0
    //水平间隔
    private(set) var itemSpacing: CGFloat = 10.0
    //边缘间隔
    private(set) var EdgInsetsDefault = UIEdgeInsetsMake(10, 10, 10, 10)
    
    //存放所有item的布局属性
    lazy var attributesArray = [UICollectionViewLayoutAttributes]()
    
    //存放所有列的当前高度
    lazy var columnHeightsArray = [CGFloat]()
    
    private var headerSize: CGSize = .zero
    private var footerSize: CGSize = .zero
    
    //collectionView的Content的高度
    private var contentHeight: CGFloat = 0
    
    
    //初始化
    override func prepare() {
        super.prepare()
        //清除高度
        self.contentHeight = 0
        self.headerSize = .zero
        self.footerSize = .zero
        columnHeightsArray.removeAll()
        attributesArray.removeAll()
        
        // 开始创建每一个item对应的布局属性
        let sectionCount: Int = self.collectionView!.numberOfSections
        
        //添加每一个item的大小位置
        for num in 0 ..< sectionCount {
            
            let indexPath = IndexPath(item: 0, section: num)
            
            //添加header
            let headerAttri = self.layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionHeader, at: indexPath)
            if let header = headerAttri {
                self.attributesArray.append(header)
                self.columnHeightsArray.removeAll()
            }
            
            //初始化y值
            let itemCount = self.collectionView!.numberOfItems(inSection: num)
            for _ in 0 ..< itemCount {
                columnHeightsArray.append(self.contentHeight)
            }
            //添加item
            for i in 0 ..< itemCount {
                let indexPat = IndexPath(item: i, section: num)
                let attrs = self.layoutAttributesForItem(at: indexPat)
                if let attri = attrs {
                    attributesArray.append(attri)
                }
            }
            
            //添加footer
            let footerAttributes = self.layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionFooter, at: indexPath)
            if let footer = footerAttributes {
                self.attributesArray.append(footer)
            }
            
        }
    }
    
    //返回indexPath位置上每一个元素的布局属性
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        
        let attrs = UICollectionViewLayoutAttributes.init(forCellWith: indexPath)
        let collectionWidth = self.collectionView?.frame.size.width
        
        //item的宽度
        let itemsWidth = (collectionWidth! - EdgInsetsDefault.left - EdgInsetsDefault.right - CGFloat(ColumnCountDefault - 1) * itemSpacing ) / CGFloat(ColumnCountDefault)
        
        //item的高度(通过代理获得文案的动态高度)
        let delegateHeight = delegate?.collectionView(collectionView!, calculateHeightAtIndexPath: indexPath) ?? 0
        let itemsHeight = itemsWidth + delegateHeight
        
        //高度最短的序列号
        var minColum: Int = 0
        //高度最短的列的高度
        var minHeight = columnHeightsArray[0]
        //历遍所有高度取出最短列的高度和序列号
        for i in 1 ..< ColumnCountDefault {
            let columnH = columnHeightsArray[i]
            if minHeight > columnH {
                minHeight = columnH
                minColum = i
            }
        }
        
        //设置每一个item的x、y点
        let x = EdgInsetsDefault.left + CGFloat(minColum) * (itemsWidth + itemSpacing)
        var y = minHeight
        //如果不是第一个,则需要加上间隔
        if y != self.EdgInsetsDefault.top {
            y += lineSpacing
        }
        
        attrs.frame = CGRect(x: x, y: y, width: itemsWidth, height: CGFloat(itemsHeight))
        
        //更新数组中最短列的高度
        columnHeightsArray[minColum] = attrs.frame.maxY
        
        if self.contentHeight < minHeight {
            self.contentHeight = minHeight
        }
        
        //取最大的高度,即下一个section与当前section的距离
        for i in 0..<self.columnHeightsArray.count {
            if self.contentHeight < self.columnHeightsArray[i] {
                self.contentHeight = self.columnHeightsArray[i]
            }
        }
        
        return attrs
    }
    
    //设置headerView、footerView的布局属性
    override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attri = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath)
        
        if elementKind == UICollectionElementKindSectionHeader {
            if let headerSize = self.delegate?.referenceSizeForHeader(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
                self.headerSize = headerSize
            }
            attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.headerSize.width, height: self.headerSize.height)
            self.contentHeight += self.headerSize.height
            
        }else if elementKind == UICollectionElementKindSectionFooter{
            if let footer = self.delegate?.referenceSizeForFooter(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
                self.footerSize = footer
            }
            attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.footerSize.width, height: self.footerSize.height)
            self.contentHeight += self.footerSize.height
        }

        return attri
    }
    
    //返回rect范围内所有元素的布局属性的数组,即collection的item的frame
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return attributesArray
    }
    
    //返回所有列的高度,即collectionView的滚动范围
    override var collectionViewContentSize: CGSize{
        return CGSize(width: self.collectionView!.frame.size.width, height: self.contentHeight)
    }
    
}




二、应用HomeWaterFallsView:
2.1写个collectionview:

        let layout = HomeWaterFallsCollectionLayout()
        layout.delegate = self
        let new = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
        new.dataSource = self
        new.backgroundColor = #colorLiteral(red: 0.6644982952, green: 0.9803921569, blue: 0.8418341308, alpha: 1)
        
        new.register(HomeWaterFallsCollectionCell.self, forCellWithReuseIdentifier: "HomeWaterFallsCollectionCell")
        new.register(HomeWaterFallsVipView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: HomeWaterFallsVipView.header)
        new.register(HomeWaterFallsFooterView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: HomeWaterFallsFooterView.footer)
        return new
    }()

2.2设置cell

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let ranList = self.vm!.randomList
        let firstList = Array(ranList.prefix(4))
        let lastList = Array(ranList.dropFirst(4))
        
        switch indexPath.section {
        case 0:
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeWaterFallsCollectionCell", for: indexPath) as! HomeWaterFallsCollectionCell
            let user = firstList[indexPath.row]
            cell.configData(user)
            
            return cell
        default:
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeWaterFallsCollectionCell", for: indexPath) as! HomeWaterFallsCollectionCell
            let user = lastList[indexPath.row]
            cell.configData(user)
            
            return cell
        }
    }

2.3设置header、footer

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        
        if kind == UICollectionElementKindSectionHeader {
            let footView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HomeWaterFallsVipView.header, for: indexPath) as! HomeWaterFallsVipView
            return footView
        }else if kind == UICollectionElementKindSectionFooter{
            let footView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HomeWaterFallsFooterView.footer, for: indexPath) as! HomeWaterFallsFooterView
            if indexPath.section == 0 {
                footView.titleLable.text = "暂无更多数据,下面为你展示随机用户"
            }else if indexPath.section == 1{
                footView.titleLable.text = "数据已加载完成"
            }
            return footView
        }else{
            return UICollectionReusableView()
        }
    }

2.4、传递高度宽度给layout:具体高度根据自己的业务需求传递,不需要的传0

extension HomeWaterFallsView: PinterestLayoutDelegate{
    
    //设置headerView高度
    func referenceSizeForHeader(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize {
        
        return CGSize(width: kScreenWidth, height: kScreenWidth/3 + 70 + 16)
    }
    //设置footerView高度(显示隐藏height给0即可)
    func referenceSizeForFooter(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize {
        
        var height: CGFloat = 0
        
        switch section {
        case 0:
            return CGSize(width: kScreenWidth, height: 60)
        case 1:
             height = self.vm?.hasNext == false ? 60:0
            return CGSize(width: kScreenWidth, height: height)
        default:
            return CGSize(width: kScreenWidth, height: height)
        }
    }
    
    //用来设置item的高度(计算文案的高度,然后通过delegate传给itemsHeight),不需要的传0
    func collectionView(_ collectionView: UICollectionView, calculateHeightAtIndexPath indexPath: IndexPath) -> CGFloat {
        
        let ranList = self.vm!.randomList
        let firstList = Array(ranList.prefix(4))//取前面4个数组放在第一个section
        let lastList = Array(ranList.dropFirst(4))//剩余的数组放在第二个section
        
        switch indexPath.section {
        case 0:
            return firstList[indexPath.row].resume?.pdesc?.getLabelHeight(constraintedWidth: kScreenWidth/2 - 40, font: UIFont.systemFont(ofSize: 14)) ?? 0
        default:
            return  lastList[indexPath.row].resume?.pdesc?.getLabelHeight(constraintedWidth: kScreenWidth/2 - 40, font: UIFont.systemFont(ofSize: 14)) ?? 0
        }
    }
    
}

四、友情练字:163咳5137659,如果对你有帮助,请当面赏我一大嘴巴子,蟹蟹

相关文章

网友评论

      本文标题:swift 布瀑流布局layout,含headerview,fo

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