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];
效果