swift 自定义collectionView流水布局

1,336 阅读2分钟

周末没有加班,闲来无事,就将之前Object-C写的代码功能块改为swift,项目重构时将会用到,改完测试后现在将代码贴出来做一个记录,接下来的时间都会是在项目重构上,leader让项目重构改为swift的, 1.图片加载是Kingfisher第三方 2.基于MVC设计模式

设计思路 1.创建继承自UICollectionViewFlowLayout的类,重写系统方法, 2.加载layout的时候这个方法override func prepare() {}调用 3.在这override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {}方法中将决定每一个item的布局位置, 4.这个方法override var collectionViewContentSize: CGSize{}设置item的大小(和oc写法有很大的区别) 详细的代码我上传到了github上 详细代码github地址 这里写图片描述

 /// 初始化
    override func prepare() {
        super.prepare()
        contentHeight = 0
        
        //清除之前计算的高度
    self.columnHeights.removeAllObjects()
        
        for _ in 0..<columCount() {
            columnHeights.add(edgeInsets().top)
        }
        
        //清除之前所有的布局
        self.attrsArray.removeAllObjects()
        ///创建每一个cell对应的布局属性
        let count:NSInteger = (collectionView?.numberOfItems(inSection: 0))!
        for i in 0..<count {
            //创建位置
            let indexpath:NSIndexPath = NSIndexPath(item: i, section: 0)
            //获取indexpath位置cell对应的布局属性
            let atts:UICollectionViewLayoutAttributes = layoutAttributesForItem(at: indexpath as IndexPath)!
            attrsArray.add(atts)
        }
    }
    //决定cell的排布位置
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return (attrsArray as! [UICollectionViewLayoutAttributes])
    }
    


//返回indexpath位置cell对应的布局属性
    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        //创建布局属性
        let attributes:UICollectionViewLayoutAttributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        //collectionview的宽度
        let collectionViewW = collectionView?.frame.size.width
    
        
        //设置布局属性的frame
        
        let w:CGFloat  = (collectionViewW! - edgeInsets().left - edgeInsets().right - CGFloat((columCount() - 1))*self.columnMargin())/CGFloat(self.columCount())
        
        let h:CGFloat = (delegate?.waterflowLayout(waterflowLayout: self, heightForItemIndex: indexPath.item, itemWidth: w))!
        //找出最短的那一列
        var desColumn = 0;
        var minColumnHeight:CGFloat = self.columnHeights[0] as! CGFloat
        for i in 0..<columCount() {
            //取第i列的高度
            let columnHeigh:CGFloat = self.columnHeights[i] as! CGFloat
            if minColumnHeight > columnHeigh {
                minColumnHeight = columnHeigh
                desColumn = i
            }
        }
        let x:CGFloat = self.edgeInsets().left + CGFloat(desColumn) * (w + columnMargin())
        var y:CGFloat = minColumnHeight;
        if y != edgeInsets().top{
            y += Rowmargin()
        }
        attributes.frame = CGRect(x: x, y: y, width: w, height: h)
        
        //跟新最短的那列的高度
        columnHeights[desColumn] = (attributes.frame.maxY)
        //记录内容的高度
        let columnheight:CGFloat = columnHeights[desColumn] as! CGFloat
        if self.contentHeight! < columnheight {
            self.contentHeight = columnheight
        }
        return attributes
    }
    override var collectionViewContentSize: CGSize{
        get{
            return CGSize(width: 0, height: self.contentHeight! + self.edgeInsets().bottom)
        }
    }
    

最后来看一下具体怎么使用

    lazy var CollectionView:UICollectionView = {
        let layout:cqWaterFlowLayout = cqWaterFlowLayout() //初始化自定义的layout,
        layout.delegate = self //这个代理必须写,因为计算高度的代理需要使用
        let collection = UICollectionView(frame:CGRect(x: 0, y: 0, width:view.frame.size.width, height:view.frame.size.height), collectionViewLayout: layout)
    collection.backgroundColor = UIColor.white
        collection.register(UINib.init(nibName: "ShopsCell", bundle: nil), forCellWithReuseIdentifier: "shops")
        collection.dataSource = self
        return collection;
    }()
extension ViewController:UICollectionViewDataSource,cqWaterFlowLayoutDelegate,UITableViewDelegate{
    
    //返回的是item的高度
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return shopsArray.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell:ShopsCell = CollectionView.dequeueReusableCell(withReuseIdentifier: "shops", for: indexPath) as! ShopsCell
          let model:Source = shopsArray[indexPath.row] as! Source
        cell.setShopsData(shop: model)
        return cell
    }
       ///item列数
    func columnCountInWaterflowLayout(waterflowLayout: cqWaterFlowLayout) -> CGFloat {
        return 3
    }
    
    func waterflowLayout(waterflowLayout: cqWaterFlowLayout, heightForItemIndex: NSInteger, itemWidth: CGFloat) -> CGFloat {
        let model:Source = shopsArray[heightForItemIndex] as! Source
        
        return itemWidth * model.h! / model.w!
    }
    ///item左右间距
    func columnMarginInWaterflowLayout(waterflowLayout: cqWaterFlowLayout) -> CGFloat {
        return 5
    }
     ///item上下的间距
    func rowMarginInWaterflowLayout(waterflowLayout: cqWaterFlowLayout) -> CGFloat {
        return 10;
    }
      ///layout距离边框的距离
    func edgeInsetsInWaterflowLayout(waterflowLayout: cqWaterFlowLayout) -> UIEdgeInsets {
        return UIEdgeInsetsMake(0, 10, 10, 10)
    }
    
}

详细的代码我上传到了github上 详细代码github地址