新建文件繼承自UICollectionViewLayout
.h內(nèi)容如下:
@class WaterFlowLayout;
@protocol WaterFlowLayoutDelegate <NSObject>
//使用delegate取得每一個Cell的高度
- (CGFloat)waterFlow:(WaterFlowLayout *)layout heightForCellAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface WaterFlowLayout : UICollectionViewLayout
//聲明協(xié)議
@property (nonatomic, weak) id <WaterFlowLayoutDelegate> delegate;
//確定列數(shù)
@property (nonatomic, assign) NSInteger colum;
//確定內(nèi)邊距
@property (nonatomic, assign) UIEdgeInsets insetSpace;
//確定每個cell之間的距離
@property (nonatomic, assign) NSInteger distance;
@end
.m實現(xiàn)內(nèi)容如下:
@interface WaterFlowLayout ()
//存儲列高的數(shù)組
@property (nonatomic, strong) NSMutableArray *columHeightArr;
//存儲所有cell的尺寸信息
@property (nonatomic, strong) NSMutableArray *cellFrameArr;
@end
@implementation WaterFlowLayout
//colum的set方法
- (void)setColum:(NSInteger)colum{
if (_colum != colum) {
_colum = colum;
//將之前的布局信息失效,重新布局
[self invalidateLayout];
}
}
//distance的set方法
- (void)setDistance:(NSInteger)distance{
if (_distance != distance) {
_distance = distance;
[self invalidateLayout];
}
}
//insetSpace的set方法
- (void)setInsetSpace:(UIEdgeInsets)insetSpace{
if (!UIEdgeInsetsEqualToEdgeInsets(_insetSpace, insetSpace)) {
_insetSpace = insetSpace;
[self invalidateLayout];
}
}
//自定義layout需要重寫下面的幾個方法
//準(zhǔn)備布局,將item的位置信息計算出來
- (void)prepareLayout{
//將位置信息和高度信息的數(shù)組實例化
[self initDataArray];
//初始化每一列的初始高度
[self initColumHeightArray];
//初始化計算出全部cell的高度,并且存入數(shù)組
[self initAllCellHeight];
}
//將位置信息和高度信息的數(shù)組實例化
- (void)initDataArray{
//記錄當(dāng)前每一列的高度,所以我們只需要列數(shù)的空間就夠了。
_columHeightArr = [NSMutableArray arrayWithCapacity:_colum];
//記錄所有cell的尺寸信息
_cellFrameArr = [NSMutableArray arrayWithCapacity:0];
}
//初始化每一列的初始高度
- (void)initColumHeightArray{
for (int i = 0; i < _colum; i++) {
[_columHeightArr addObject:@(_insetSpace.top)];
}
}
//初始化計算出全部cell的高度,并且存入數(shù)組
- (void)initAllCellHeight{
//拿出第一組的全部cell的數(shù)量
NSInteger allCellNumber = [self.collectionView numberOfItemsInSection:0];
//取得整個collectionView的寬度
CGFloat totalWidth = self.collectionView.frame.size.width;
//取得一行中Cell的總寬度
CGFloat itemAllWidth = totalWidth - _insetSpace.left - _insetSpace.right - _distance * (_colum - 1);
//取得每一個cell的寬度
CGFloat width = itemAllWidth/_colum;
//循環(huán)計算每一個cell的高度并且將位置信息添加到數(shù)組中
for (int i = 0; i < allCellNumber; i++) {
//拿到當(dāng)前的列的信息
NSInteger currentColum = [self getShortColum];
//x偏移就是用當(dāng)前的列去乘以寬度和間距,并且加上內(nèi)邊距
CGFloat xOffset = _insetSpace.left + currentColum * (width + _distance);
//制造索引路徑
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
//取得y偏移
CGFloat yOffset = [[_columHeightArr objectAtIndex:currentColum] floatValue] + _distance;
//取得高度,由實現(xiàn)協(xié)議者提供
CGFloat height = 0.f;
if (_delegate && [_delegate respondsToSelector:@selector(waterFlow:heightForCellAtIndexPath:)]) {
height = [_delegate waterFlow:self heightForCellAtIndexPath:indexPath];
}
//整理cell的尺寸信息
CGRect frame = CGRectMake(xOffset, yOffset, width, height);
//attributes是用來存儲當(dāng)前indexPath的cell的位置信息的
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = frame;
//將位置信息添加到cell尺寸數(shù)組中
[_cellFrameArr addObject:attributes];
//改變當(dāng)前列的高度
_columHeightArr[currentColum] = @(frame.size.height + frame.origin.y);
}
}
//取得當(dāng)前cell的尺寸
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
return [_cellFrameArr objectAtIndex:indexPath.item];
}
//根據(jù)rect去找出需要布局的cell的位置信息
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
//用來存儲可以展示的cell的位置信息
NSMutableArray *temp = [NSMutableArray arrayWithCapacity:0];
for (UICollectionViewLayoutAttributes *attributes in _cellFrameArr) {
//如果取出的位置信息,在rect的范圍內(nèi),就將這個位置信息,裝入數(shù)組中。
if (CGRectIntersectsRect(attributes.frame, rect)) {
[temp addObject:attributes];
}
}
return temp;
}
//指定collection的contentSize
- (CGSize)collectionViewContentSize{
//內(nèi)容寬度指定為collectionView的寬度(橫向不發(fā)生滾動)
CGFloat width = self.collectionView.frame.size.width;
//取出最長的列,將其高度定位長度
CGFloat height = [self getLongColum];
return CGSizeMake(width, height);
}
- (CGFloat)getLongColum{
//記錄當(dāng)前最長的列號
__block NSInteger currentColum = 0;
//假設(shè)最長的列高度為0
__block CGFloat longHeight = 0;
//枚舉數(shù)組中的元素
[_columHeightArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj floatValue] > longHeight) {
longHeight = [obj floatValue];
currentColum = idx;
}
}];
return longHeight + _insetSpace.bottom;
}
//取得最短的列
- (NSInteger)getShortColum{
//記錄當(dāng)前最短的列號
__block NSInteger currentColum = 0;
//假設(shè)最短的列高度為float的最大值
__block CGFloat shortHeight = MAXFLOAT;
//枚舉數(shù)組中的元素
[_columHeightArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj floatValue] < shortHeight) {
shortHeight = [obj floatValue];
currentColum = idx;
}
}];
return currentColum;
}
@end