UICollectionView实现瀑布流布局

因为前面的文章已经对UICollectionVie和UICollectionViewLayout做了详细解说,在此就不再在次说明了,直接贴出UICollectionViewLayout类中的代码!

#import "WaterFlowLayout.h"

#define JPCollectionW self.collectionView.frame.size.width

/** 每一行之间的间距 */

static const CGFloat JPDefaultRowMargin = 10;

/** 每一列之间的间距 */

static const CGFloat JPDefaultColumnMargin = 10;

/** 每一列之间的间距 top, left, bottom, right */

static const UIEdgeInsets JPDefaultInsets = {0, 10, 10, 10};

/** 默认的列数 */

static const int JPDefaultColumsCount = 3;


@interface WaterFlowLayout()

/** 每一列的最大Y */

@property (nonatomic, strong) NSMutableArray *columnMaxYs;

/** 存放所有cell的布局属性 */

@property (nonatomic, strong) NSMutableArray *attrsArray;

@end


@implementation WaterFlowLayout

#pragma mark - 懒加载

- (NSMutableArray *)columnMaxYs

{

    if (!_columnMaxYs) {

        _columnMaxYs = [[NSMutableArray alloc] init];

    }

    return _columnMaxYs;

}

- (NSMutableArray *)attrsArray

{

    if (!_attrsArray) {

        _attrsArray = [[NSMutableArray alloc] init];

    }

    return _attrsArray;

}


#pragma mark - 实现内部的方法

// 设置contentSize 每次滚动都会调用

- (CGSize)collectionViewContentSize

{

    // 找出最长那一列的最大Y

    CGFloat destMaxY = [[self.columnMaxYs valueForKeyPath:@"@max.floatValue"] floatValue];

    return CGSizeMake(0, destMaxY + JPDefaultInsets.bottom);

}


// 设置初始化的东西 该方法在每次刷新的时候都会调用,滚动时不会调用

- (void)prepareLayout

{

    [super prepareLayout];

    // 重置每一列的最大Y值,即初始化

    [self.columnMaxYs removeAllObjects];

    for (NSUInteger i = 0; i<JPDefaultColumsCount; i++) {

        [self.columnMaxYs addObject:@(JPDefaultInsets.top)];

    }

    // 计算所有cell的布局属性

    [self.attrsArray removeAllObjects];

    NSUInteger count = [self.collectionView numberOfItemsInSection:0];

    for (NSUInteger i = 0; i < count; ++i) {

        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];

        UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];

        [self.attrsArray addObject:attrs];

    }

}


// 设置所有元素(比如cell、补充控件、装饰控件)的布局属性 每次滚动都会调用

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

{

    return self.attrsArray;

}


// 说明indexPath对应每一个cell的布局属性 该方法在每次刷新的时候都会调用,滚动时不会调用

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

{

    UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    /** 计算indexPath位置cell的布局属性 */

    // 水平方向上的总间距

    CGFloat xMargin = JPDefaultInsets.left + JPDefaultInsets.right + (JPDefaultColumsCount - 1) * JPDefaultColumnMargin;

    // cell的宽度

    CGFloat w = (JPCollectionW - xMargin) / JPDefaultColumsCount;

    // cell的高度,测试数据,随机数

    CGFloat h = 50 + arc4random_uniform(150);

    

    // 找出最短那一列的 列号 最大Y

    CGFloat destMaxY = [self.columnMaxYs[0] doubleValue];

    NSUInteger destColumn = 0;

    for (NSUInteger i = 1; i<self.columnMaxYs.count; i++) {

        // 取出第i列的最大Y

        CGFloat columnMaxY = [self.columnMaxYs[i] doubleValue];

        // 找出数组中的最小值

        if (destMaxY > columnMaxY) {

            destMaxY = columnMaxY;

            destColumn = i;

        }

    }

    // cellx

    CGFloat x = JPDefaultInsets.left + destColumn * (w + JPDefaultColumnMargin);

    // celly

    CGFloat y = destMaxY + JPDefaultRowMargin;

    // cellframe

    attrs.frame = CGRectMake(x, y, w, h);

    

    // 更新数组中的最大Y

    self.columnMaxYs[destColumn] = @(CGRectGetMaxY(attrs.frame));

    return attrs;

}


@end



猜你喜欢

转载自blog.csdn.net/pbz106/article/details/53837531