iOS-Swift3瀑布流布局开源

转载注明出处: http://blog.csdn.net/qxuewei/article/details/53490560
在项目中偶尔会用到瀑布流的布局,目前多数直播类软件,信息展示类软件等
接下来分析一种简单的实现方法,利用swift3实现.

这里写图片描述

在实现这种瀑布流首先想到的是使用UICollectionView实现,类似于不规则的流水布局.我们可以通过自定义 UICollectionViewFlowLayout ,将collectionView的item通过我们想要的格式显示

核心代码:
自定义UICollectionViewFlowLayout 类 XWWaterFallLayout

//
//  XWWaterFallLayout.swift
//  XWWaterFallSwiftDemo
//
//  Created by 邱学伟 on 2016/12/6.
//  Copyright © 2016年 邱学伟. All rights reserved.
//

import UIKit

//MARK: - 数据源协议
protocol XWWaterFallLayoutDataSource : class {
    func numberOfCols(_waterFallLayout : XWWaterFallLayout) -> Int
    func itemHeight(_waterFallLayout : XWWaterFallLayout, item : Int) -> CGFloat
}

class XWWaterFallLayout: UICollectionViewFlowLayout {
    weak var dataSource : XWWaterFallLayoutDataSource?
    fileprivate lazy var cellAttributes : [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()
    fileprivate lazy var cols : Int = {
        return self.dataSource?.numberOfCols(_waterFallLayout: self) ?? 2
    }()
    fileprivate lazy var totalHeight : [CGFloat] = Array(repeating: 0.0, count: self.cols)
}

//MARK: - 准备布局
extension XWWaterFallLayout {
    override func prepare() {
        super.prepare()

        let itemCount : Int = collectionView!.numberOfItems(inSection: 0)
        //为每个cell创建 UICollectionViewLayoutAttributes(决定cell位置)
        let width : CGFloat = (collectionView!.bounds.width - sectionInset.left - sectionInset.right - CGFloat(cols - 1) * minimumInteritemSpacing) / CGFloat(cols)
        for i in 0..<itemCount {
            let indexPath : IndexPath = IndexPath(item: i, section: 0)
            let attributes : UICollectionViewLayoutAttributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)

            let minH : CGFloat = totalHeight.min()!
            let minIndex = totalHeight.index(of: minH)!
            let X : CGFloat = sectionInset.left + (minimumInteritemSpacing + width) * CGFloat(minIndex)
            let Y : CGFloat = minH + minimumLineSpacing
            guard let height : CGFloat = dataSource?.itemHeight(_waterFallLayout: self, item: i) else {
                fatalError("请遵守数据源实现对应方法返回cell高度")
            }
            attributes.frame = CGRect(x: X, y: Y, width: width, height: height)
            cellAttributes.append(attributes)
            totalHeight[minIndex] = minH + minimumLineSpacing + height
        }
    }
}

//MARK: - 返回布局
extension XWWaterFallLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        return cellAttributes
    }
}

//MARK: - 设置ContentSize
extension XWWaterFallLayout {
    override var collectionViewContentSize: CGSize{
        return CGSize(width: collectionView!.bounds.width, height: totalHeight.max()! + sectionInset.bottom)
    }
}

在使用中,直接在定义collectionView中使用自定义Layout

//通过自定义layout改变collectionView的布局
        let layout : XWWaterFallLayout = XWWaterFallLayout()
        let itemMargin : CGFloat = 10
        layout.minimumLineSpacing = itemMargin
        layout.minimumInteritemSpacing = itemMargin
        layout.sectionInset = UIEdgeInsets(top: itemMargin, left: itemMargin, bottom: itemMargin, right: itemMargin)
        layout.dataSource = self

        let collectionView : UICollectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
        collectionView.dataSource = self

需要注意的是,所封装的Layout需要外界传入item的行数和每个item的高度.需要实现自定义layout的数据源方法

//MARK: - XWWaterFallLayoutDataSource数据源方法
extension ViewController : XWWaterFallLayoutDataSource {
    func numberOfCols(_waterFallLayout: XWWaterFallLayout) -> Int {
        return 4
    }
    func itemHeight(_waterFallLayout: XWWaterFallLayout, item: Int) -> CGFloat {
        return CGFloat(arc4random_uniform(200) + 100)
    }
}

项目完整Demo链接:https://github.com/qxuewei/XWWaterFallSwift

猜你喜欢

转载自blog.csdn.net/qiuxuewei2012/article/details/53490560