本文主要介绍自定义UICollectionView布局类UICollectionViewLayout,实现简单瀑布流视图。
利用自定义UICollectionViewLayout类实现瀑布流步骤:
- 新建继承自UICollectionViewLayout的类。
- 重写以下方法。
下面介绍一下需要在UICollectionViewLayout子类中需要重写的方法,如下:
- 重写prepareLayout函数:预加载布局函数
/**
* 重写预加载布局函数,只会被执行一次
*/
- (void)prepareLayout {
[super prepareLayout];
// 初始化必要数据
// 如:cell个数([self.collectionView numberOfSections]),cell宽度等
// 初始化必要数据
[self setupInitData];
// 计算宽度
[self setupCellWidth];
// 随机高度
[self setupCellHeight];
}
/**
* 生成cell的随机高度,模拟不等高现象
*/
- (void)setupCellHeight {
self.cellHeightArray = [[NSMutableArray alloc] initWithCapacity:self.numberCellsInSections];
for (int i = 0 ; i < self.numberCellsInSections; i ++) {
CGFloat cellHeight = arc4random() % (int)(self.cellMaxHeight - self.cellMinHeight) +
self.cellMinHeight;
[_cellHeightArray addObject:@(cellHeight)];
}
}
/**
* 计算cell的宽度
*/
- (void)setupCellWidth {
// 每列cell的宽度相同
self.cellWidth = (SCREEN_WIDTH - (HXColumnCount - 1) * HXCellsMargin) / HXColumnCount;
// 计算每个cell的x坐标
self.cellXArray = [[NSMutableArray alloc] initWithCapacity:HXColumnCount];
for (int i = 0 ; i < HXColumnCount; i ++) {
CGFloat tempX = i * (self.cellWidth + HXCellsMargin);
[self.cellXArray addObject:@(tempX)];
}
}
- (void)setupInitData {
self.numberOfSections = [self.collectionView numberOfSections];
self. numberCellsInSections = [self.collectionView numberOfItemsInSection:0];
// 约束自动生成的图片的高度在100-200之间
self.cellMinHeight = 100;
self.cellMaxHeight = 200;
}
- 重写collectionViewContentSize函数:设置滚动范围
/**
* 重设滚动范围
*/
- (CGSize)collectionViewContentSize {
CGFloat height = [self cellMaxYWithArray:self.cellYArray];
return CGSizeMake(SCREEN_WIDTH, height);
}
- (CGFloat)cellMaxYWithArray:(NSMutableArray *)array {
if (array.count == 0) {
return 0.0;
}
CGFloat cellMaxY = [array[0] floatValue];// 默认第一个最大
for (NSNumber *num in array) {
CGFloat tempY = [num floatValue];
if (tempY > cellMaxY) {
cellMaxY = tempY;
}
}
return cellMaxY;
}
- 重写layoutAttributesForElementsInRect:函数:给每个cell绑定一个layoutAttributes属性,并返回
/**
* 重写该方法,返回每个cell的layoutAttributes属性
* 给每个cell绑定一个layoutAttributes属性
*/
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
[self initCellYArray];// 初始化存储每列cell的y值数组
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < self.numberCellsInSections; i ++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
[array addObject:attributes];
}
return array;
}
- (void)initCellYArray {
self.cellYArray = [[NSMutableArray alloc] initWithCapacity:HXColumnCount];
for (int i = 0; i < HXColumnCount; i ++) {
[self.cellYArray addObject:@(0)];
}
}
- 重写layoutAttributesForItemAtIndexPath:函数:制定每个cell的layoutAttributes属性
/**
* 指定每个cell的layoutAttributes属性
*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGRect frame = CGRectZero;
CGFloat cellHeight = [self.cellHeightArray[indexPath.row] floatValue];
int minYindex = [self cellMinYIndexWithArray:self.cellYArray];
CGFloat tempX = [self.cellXArray[minYindex] floatValue];
CGFloat tempY = [self.cellYArray[minYindex] floatValue];
frame = CGRectMake(tempX, tempY, self.cellWidth, cellHeight);
self.cellYArray[minYindex] = @(tempY + cellHeight + HXCellsMargin);
// 绑定
attributes.frame = frame;
return attributes;
}
- (int)cellMinYIndexWithArray:(NSMutableArray *)array {
if (array.count == 0) {
return 0.0;
}
// 默认最小Y值、以及最小Y值对应的索引
CGFloat min = [array[0] floatValue];
int minIndex = 0;
for (int i = 0 ; i < array.count; i ++) {
CGFloat temp = [array[i] floatValue];
if (temp < min) {
min = temp;
minIndex = i;
}
}
return minIndex;
}
自定义完UICollectionViewLayout子类后,在控制器中使用它,如下:
- (void)viewDidLoad {
[super viewDidLoad];
// 设置collectionView布局方式
<span style="color:#FF0000;">HXCollectionViewFallLayout</span> *fallLayout = [[<span style="color:#FF0000;">HXCollectionViewFallLayout</span> alloc] init];
// 创建collectionView
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:fallLayout];
// 设置collectionView背景颜色
collectionView.backgroundColor = [UIColor redColor];
// 设置数据源和代理
collectionView.dataSource = self;
collectionView.delegate = self;
// 注册一个collectionView Cell
[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"COLLECTIONCELL"];
[self.view addSubview:collectionView];
self.collectionView = collectionView;
}
将UICollectionView的布局模式设置成自定义的布局即可。