最近开发中遇到了关于瀑布流布局的需求,所有就整理了一个瀑布流布局类,使用时只需要调整列数、行间距、列间距、上下左右边缘就可以做出各种需求的瀑布流布局,下面直接上代码:
自定义瀑布流需要继承UICollectionViewLayout布局类
.h文件
#import <UIKit/UIKit.h>
@interface ZYYWaterLayout :UICollectionViewLayout
@end
.m文件
#import "ZYYWaterLayout.h"
//默认的列数
staticconst CGFloat ZYYCollumCoutnt =3;
//列间距
staticconst CGFloat ZYYCollumMargin =10;
//行间距
staticconst CGFloat ZYYRowMargin =10;
//边缘间距
staticconst UIEdgeInsets ZYYEdgeUnsets = {10,10,10,10};
@interfaceZYYWaterLayout()
//用于存放cell属性的数组
@property (strong,nonatomic)NSMutableArray *attrsArray;
//用于存放所有列高度数组
@property (strong,nonatomic)NSMutableArray *maxH;
@end
@implementation ZYYWaterLayout
//懒加载属性数组
- (NSMutableArray *)attrsArray{
if (_attrsArray ==nil) {
_attrsArray = [NSMutableArrayarray];
}
return_attrsArray;
}
//懒加载高度属性数组
- (NSMutableArray *)maxH{
if (_maxH ==nil) {
_maxH = [NSMutableArrayarray];
}
return_maxH;
}
//准备布局每次刷新都会调用此方法
- (void)prepareLayout{
[superprepareLayout];
//先清除以前计算的所有高度,这种做法比较严谨,如果有下拉刷新,不及时清空数组的话会造成数据混乱
[self.maxHremoveAllObjects];
//这里先将数组里面的初始值设为0
for (NSInteger i =0; i < ZYYCollumCoutnt; i ++) {
[self.maxHaddObject:@0];
}
NSLog(@"%s",__func__);
//清除以前的所有属性
[self.attrsArrayremoveAllObjects];
//开始创建每个cell对应的布局属性
//1、获取collectionView里面的有多少个item
NSInteger count = [self.collectionViewnumberOfItemsInSection:0];
//创建多少collectionViewcell属性
for (NSInteger i=1; i<count; i++) {
//获取item对应的indexPath
NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];
//创建属性调用下面的layoutAttributesForItemAtIndexPath方法
UICollectionViewLayoutAttributes *attrs = [selflayoutAttributesForItemAtIndexPath:indexPath];
//设置cell的属性直接调用layoutAttributesForItemAtIndexPath方法即可
[self.attrsArrayaddObject:attrs];
}
}
/**
* 决定布局的关键所在
*
* @param rect 属性rect
*
* @return 返回属性数组
*/
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSLog(@"%s",__func__);
returnself.attrsArray;
}
/**
* 返回indexPath位置cell对应的布局属性
* 这个方法是核心算法
*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
//创建属性
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];
//collectionView的宽度
CGFloat collectionViewW =self.collectionView.frame.size.width;
//列号
NSInteger cloumIndex =0;
//默认第一行是最小的,这样做的话可以让下面的for循环从i=1开始遍历,这样做可以优化性能
CGFloat minClumnHeight = [self.maxH[0]doubleValue];
for (NSInteger i =1; i < ZYYCollumCoutnt; i++) {
//取出第i列元素的y值
CGFloat cheight = [self.maxH[i]doubleValue];
if (minClumnHeight > cheight) {
minClumnHeight = cheight;
cloumIndex = i;
}
}
//每个item的宽度 == (collectionView的宽度 -左边距 -右边距 -(列数-1)*间距)再除于列数
CGFloat w = (collectionViewW -ZYYEdgeUnsets.left -ZYYEdgeUnsets.right - (ZYYCollumCoutnt -1) * ZYYCollumMargin)/3.0;
//高度这里用的是随机数,做项目时根据的是素材的高度
CGFloat h =50 + arc4random_uniform(100);
//x可以根据列来算
CGFloat x =ZYYEdgeUnsets.left + cloumIndex * (ZYYRowMargin + w);
//y最小itme值计算
CGFloat y = minClumnHeight +ZYYRowMargin;
//设置布局属性的frame,这个frame是最终item的frame
attrs.frame =CGRectMake(x, y, w, h);
//更新最短那列的高度
self.maxH[cloumIndex] =@(CGRectGetMaxY(attrs.frame));
return attrs;
}
//尺寸
- (CGSize)collectionViewContentSize{
//找出y值最大的的那一列,和上面找出最小高度相似
CGFloat maxColunmHeight = [self.maxH[0]doubleValue];
for (NSInteger i =1; i < ZYYCollumCoutnt; i++) {
CGFloat my = [self.maxH[i]doubleValue];
if (maxColunmHeight < my) {
maxColunmHeight = my;
}
}
returnCGSizeMake(0, maxColunmHeight +ZYYEdgeUnsets.bottom);
}
结语:上面的注释比较清楚,用的时候直接将代码复制粘贴就可以使用了
@end