欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

UICollectionView自定义layout如何实现? 比如瀑布流

程序员文章站 2024-03-24 09:50:40
...

实现UICollectionView自定义layout的方法:自定义一个类继承自UICollectionViewLayout类,重写下面方法:

//collectionview的内容尺寸
- (CGSize)collectionViewContentSize;
- (void)prepareLayout;

//返回所有元素的布局属性
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
//返回对应indexPath的cell的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
//返回对应于indexPath追加视图的布局属性,如果没有追加视图可不重载
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
//返回对应于indexPath装饰视图的布局属性,如果没有追加视图可不重载
- (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
//当边界发生改变时,是否应该刷新布局。如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息。
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

自定义一个类WaterfallCollectionViewLayout继承自UICollectionViewLayout类    重写上面方法实现瀑布流布局


#import "WaterfallCollectionViewLayout.h"


//行距
static const CGFloat rowMargin = 10;
//列距
static const CGFloat columnMargin = 10;

static const UIEdgeInsets insets = {10, 10, 10, 10};

//列数
static const int columns = 3;

@interface WaterfallCollectionViewLayout()

//每一列的最大Y值
@property (nonatomic, strong) NSMutableArray *columnsMaxYarray;

//存放所有cell的布局属性
@property (nonatomic, strong) NSMutableArray *cellAttrisArray;

@end

@implementation WaterfallCollectionViewLayout

//懒加载
- (NSMutableArray *)columnsMaxYarray {
    if (!_columnsMaxYarray) {
        _columnsMaxYarray = [NSMutableArray array];
    }
    return _columnsMaxYarray;
}
- (NSMutableArray *)cellAttrisArray {
    if (!_cellAttrisArray) {
        _cellAttrisArray = [NSMutableArray array];
    }
    return _cellAttrisArray;
}


//collectionview的内容尺寸
- (CGSize)collectionViewContentSize {
    CGFloat maxY = [self.columnsMaxYarray[0] doubleValue];
    for (int i = 0; i < self.columnsMaxYarray.count; i++) {
        CGFloat columnY = [self.columnsMaxYarray[i] doubleValue];
        if (maxY < columnY) {
            maxY = columnY;
        }
    }
    return CGSizeMake(10, maxY + insets.bottom);
}


- (void)prepareLayout {
    [super prepareLayout];
    
    //重置每一列的最大Y值
    [self.columnsMaxYarray removeAllObjects];
    for (int i = 0; i < columns; i++) {
        [self.columnsMaxYarray addObject:@(insets.top)];
    }
    
    //计算所有cell的布局属性
    [self.cellAttrisArray removeAllObjects];
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (NSInteger i = 0; i < count; i++) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
        UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
        [self.cellAttrisArray addObject:attributes];
    }
}


//返回所有元素的布局属性
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
    return self.cellAttrisArray;
}

//返回对应indexPath的cell的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    //水平方向总间距
    CGFloat xMargin = insets.left + insets.right + (columns - 1)*columnMargin;
    //cell的宽度
    CGFloat w = (_totalWidth - xMargin)/columns;
    
    //cell?的高度
    CGFloat h = 50 + arc4random_uniform(150);
    
    //找最短的列号  和高度值
    CGFloat minY = [self.columnsMaxYarray[0] doubleValue];
    NSInteger minColumn = 0;
    for (int i = 0; i < self.columnsMaxYarray.count; i++) {
        CGFloat columnMaxY = [self.columnsMaxYarray[i] doubleValue];
        
        if (minY > columnMaxY) {
            minY = columnMaxY;
            minColumn = i;
        }
    }
   
   //cell的x值
    CGFloat x = insets.left + minColumn * (w + columnMargin);
    //cell的y值
    CGFloat y = minY + rowMargin;
    
    //cell的frame
    attribute.frame = CGRectMake(x, y, w, h);
    
    self.columnsMaxYarray[minColumn] = @(CGRectGetMaxY(attribute.frame));
    
    return attribute;
}



@end


调用

WaterfallCollectionViewLayout *layout = [[WaterfallCollectionViewLayout alloc]init];
    layout.totalWidth = 375;
    UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, 375, 667) collectionViewLayout:layout];

效果

UICollectionView自定义layout如何实现? 比如瀑布流