UICollectionView的瀑布流实现就是继承与UICollectionViewLayout重写一个类,在此类中重写prepare方法等(在dome中有详细注释),主要思想就是计算了在视图中的Cell的X和Y的值,也就是Cell的位置,因为瀑布流的每个cell的高度不同,所有在排列的时候要找到上一列中那一列的最大Y值是最小的,在这一列中添加下一个Cell.

以下方法为主要方法:

-(void)prepareLayout

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
-(CGSize)collectionViewContentSize
#import "WHYcollectionLayout.h"
默认的列数
//static NSInteger const WHYDefaultColums = 2;
行距间隙
//static CGFloat const WHYDefaultRowMargin = 10;
列距间隙
//static CGFloat const WHYDefaultColumsMargin = 10;
他是一个结构体 赋值进行大括号 上左下右间距默认的边距
//static UIEdgeInsets const WHYdefultinsets = {10,10,10,10};
@interface WHYcollectionLayout ()
//定义数字记录所有最大的Y值以便以后比较,找出最短的列
@property(nonatomic,strong)NSMutableArray *maxCoulumnYs;
//定义数组保存所有子空间的布局对象
@property(nonatomic,strong)NSMutableArray *attrsArray;
 
@end
 
@implementation WHYcollectionLayout
 
//当滚动的时候会循环调用layoutAttributesForElementsInRect方法
//因为第一次调用完毕layoutAttributesForElementsInRect方法

-(NSMutableArray *)maxCoulumnYs{
    if (!_maxCoulumnYs) {
        _maxCoulumnYs = [NSMutableArray array];
初始化所有列的默认值
        for (int i = 0 ; i < _WHYDefaultColums ; i++) {
顶部间隙的默认值
            _maxCoulumnYs[i] = @(_WHYdefultinsets.top);
        }
    }
    return  _maxCoulumnYs;
}
 
//布局是调用
//第一次显示的时候调用
//一般情况下调用reloadData的时候调用
-(void)prepareLayout{
    [super prepareLayout];
     
    //每次计算之重置保存每一列的最大Y值得数据
    [self.maxCoulumnYs removeAllObjects];
    for (int i = 0 ; i < _WHYDefaultColums ; i++) {
顶部间隙的默认值
        _maxCoulumnYs[i] = @(_WHYdefultinsets.top);
    }

    

    

获取当前collectionView中有多少个子控件

NSInteger  count = [self.collectionView numberOfItemsInSection:0];
    //利用循环创建所有子控件对应的对象
    NSMutableArray *arrayM = [NSMutableArray array];
    for (int i = 0 ; i < count ; i++) {
        NSIndexPath *path  = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *atts = [self layoutAttributesForItemAtIndexPath:path];
        //将属性对象添加到数组中
        [arrayM addObject:atts];
    }
    //返回存储子视图控件属性的数组
    self.attrsArray = arrayM;
     
}
//该方法用于返回collectionView上所有子视图的排布
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
   /* //每次计算之重置保存每一列的最大Y值得数据
    [self.maxCoulumnYs removeAllObjects];
    for (int i = 0 ; i < WHYDefaultColums ; i++) {
顶部间隙的默认值
        _maxCoulumnYs[i] = @(WHYdefultinsets.top);
    }
 
获取当前collectionView中有多少个子控件
    NSInteger  count = [self.collectionView numberOfItemsInSection:0];
    //利用循环创建所有子控件对应的对象
    NSMutableArray *arrayM = [NSMutableArray array];
    for (int i = 0 ; i < count ; i++) {
        NSIndexPath *path  = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes *atts = [self layoutAttributesForItemAtIndexPath:path];
        //将属性对象添加到数组中
        [arrayM addObject:atts];
    }
    //返回存储子视图控件属性的数组
    return arrayM;
    */
    return self.attrsArray;
}
//用于反悔指定的子视图的布局对象
//一个UIcollectionViewLayoutAttributtes对象就对应一个子控件的排布
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
     
    //创建对应位置的布局对象
#warning  创建的时候不能通过alloc  init来创建布局对象的!因为如果通过alloc init来创建,系统不知道要创建的属性属于(cell装饰视图 补充视图)
    UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
计算frame
宽度 = UICollectionView高度 -左边间隙 - 右边间隙 —  中间间隙
总的间隙
    CGFloat totaMargin = _WHYdefultinsets.left + _WHYdefultinsets.right + (_WHYDefaultColums - 1)*_WHYDefaultColumsMargin;
    CGFloat width = (self.collectionView.frame.size.width - totaMargin)/_WHYDefaultColums;
高度
//    CGFloat height = 50 + arc4random_uniform(200);
    CGFloat height = [self.delegate colltecionViewCellHeightandIndexPath:indexPath];
     
找到最短的列数\
    以及最最短列的最大Y值
     
    //取出第0列的Y值,假设第0列的Y值最小;
    CGFloat destY = [self.maxCoulumnYs[0] doubleValue];
    NSUInteger desxtIndex = 0;
    for (int i = 1 ; i < _WHYDefaultColums; i++) {
取出其它列依次比较
        CGFloat tempY = [self.maxCoulumnYs[i] doubleValue];
        if (destY > tempY) {
            destY = tempY;
            desxtIndex = i;
        }
    }
左边的边距 +(item的宽度 +间隙) * 列号
    CGFloat x = _WHYdefultinsets.left + (width + _WHYDefaultRowMargin)* desxtIndex;
 
最短的最大的Y
    CGFloat y = destY + _WHYDefaultRowMargin;
     
    //设置子控件的位置
    attr.frame = CGRectMake(x, y, width, height);
     
更新当前列的Y值
    self.maxCoulumnYs[desxtIndex] = @(CGRectGetMaxY(attr.frame));
     
    return attr;
}
//返回collectionView
-(CGSize)collectionViewContentSize{
    //计算其中一列的最大的Y值
    CGFloat destY = [self.maxCoulumnYs[0] doubleValue];
    for (int i = 1 ; i < _WHYDefaultColums; i++) {
取出其它列依次比较
        CGFloat tempY = [self.maxCoulumnYs[i] doubleValue];
        if (destY < tempY) {
            destY = tempY;
        }
    }
    return CGSizeMake(0, destY + _WHYdefultinsets.bottom);
}

@end


第一次写博客  若有问题请与本人联系,希望能帮到大家。