19、UICollectionView实现自动换行和自动计算collectionView高度

需求:
(1)后面空间不足的时候自动换行
(2)自动计算出UICollectionView的行高
在这里插入图片描述

import Foundation

//UICollectionView自动换行

/// 对齐方向的枚举,
enum AlignDirection: Int {
    case left = 0,       //左对齐
         rightFlow,  //右对齐  左起显示
         rightData,  //右对齐  右起显示
         center      //中间对齐
}

class CollectionViewAlignFlowLayout: UICollectionViewFlowLayout {
    //默认向左对齐
    var alignDirection: AlignDirection = .left
    //所有cell的布局属性
    var layoutAttributes: [UICollectionViewLayoutAttributes] = []
    //计算出总高度
    var caculateTotalHeight:((_ height:CGFloat)->())?
    
    //collectionViewContentSize collectionView的实际大小
    private var contentSize: CGSize = CGSize.zero
    
    override var collectionViewContentSize: CGSize {
        if self.scrollDirection == .vertical {
            return CGSize.init(width: self.collectionView!.frame.width, height: contentSize.height)
        }
        return CGSize.init(width: contentSize.width, height: self.collectionView!.frame.height)
    }
    
    override init() {
        super.init()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    //预加载布局属性
    override func prepare() {
        super.prepare()
        contentSize = CGSize.zero
        //目前只考虑单个分组的实现
        let itemNum: Int = self.collectionView!.numberOfItems(inSection: 0)
        //清空旧布局
        layoutAttributes.removeAll()
        for i in 0..<itemNum {
            //计算布局属性
            let layoutAttr = layoutAttributesForItem(at: IndexPath.init(row: i, section: 0))
            layoutAttributes.append(layoutAttr!)
            if i == itemNum - 1 {
                caculateTotalHeight?(layoutAttr!.frame.maxY)
            }
        }
    }
    
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        //size默认为itemSize
        var size = self.itemSize
        //从代理方法获取item的size
        if self.collectionView!.delegate != nil && self.collectionView!.delegate!.conforms(to: UICollectionViewDelegateFlowLayout.self) && self.collectionView!.delegate!.responds(to: #selector(UICollectionViewDelegateFlowLayout.collectionView(_:layout:sizeForItemAt:)))  {
            //转换对象
            let flowLayoutDelegate = self.collectionView!.delegate as! UICollectionViewDelegateFlowLayout
            size = flowLayoutDelegate.collectionView!(self.collectionView!, layout: self, sizeForItemAt: indexPath)
        }
        //初始化每个item的frame
        var frame = CGRect.zero
        //初始化x, y
        var x: CGFloat = 0
        var y: CGFloat = 0
        //从layoutAttributes中获取上一个item 如果获取不到 设置现在的item为第一个item
        //判断collectionView的滑动方向
        if self.scrollDirection == .vertical {
            //获取collectionView的宽度
            let collectionViewWidth: CGFloat = self.collectionView!.bounds.width
            //根据对齐方向设置坐标的初始值
            if alignDirection == .left {
                //左对齐
                x = self.sectionInset.left
                y = self.sectionInset.top
                //判断是否上一个item
                if layoutAttributes.count>0 {
                    //获取上一个item
                    let lastLayoutAttr = layoutAttributes.last!
                    //判断当前行的宽度是否足够插入新的item
                    if lastLayoutAttr.frame.maxX+self.minimumInteritemSpacing+size.width+self.sectionInset.right>collectionViewWidth {
                        //如果宽度总和超过总宽度, 改变y坐标, 当前的item在下一行显示
                        y = lastLayoutAttr.frame.maxY+self.minimumLineSpacing
                    }else{
                        //如果宽度可以插入item, 修改坐标点, y轴与上一个item平齐, x轴则为上一个item的最右边加上行间距
                        x = lastLayoutAttr.frame.maxX+self.minimumInteritemSpacing
                        y = lastLayoutAttr.frame.minY
                    }
                }
            }
        }else {
            //水平方向滑动
            let layoutAttr = super.layoutAttributesForItem(at: indexPath)!
            x = layoutAttr.frame.origin.x
            y = layoutAttr.frame.origin.y
        }
        frame = CGRect(x: x, y: y, width: size.width, height: size.height)
        //更新contentSize, 此处赋值有时候不是最大值, 如果需要用到collectionViewContentSize这个属性, 需要判断新的值是否比原值大
        contentSize.width = frame.maxX+self.sectionInset.right
        contentSize.height = frame.maxY+self.sectionInset.bottom
        //创建每个item对应的布局属性
        let layoutAttr = UICollectionViewLayoutAttributes.init(forCellWith: indexPath)
        layoutAttr.frame = frame
        return layoutAttr
    }
    //返回所有布局
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return layoutAttributes
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值