继承UICollectionViewLayout
@interface WaterPullLayout : UICollectionViewLayout
需要两个数组来保存每个item的属性和每列的总高度
@interface WaterPullLayout ()
{
/**
* 保存每个item的属性
*/
NSMutableArray *_itemAttributes;
/**
* 保存每列的高度
*/
NSMutableArray *_columnHeights;
}
.m实现必须重写四个方法:
-//对item布局,reloadData会触发
- (void)prepareLayout
- //返回指定区域的item的属性对象数组
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
-//返回指定indexPath的item的属性对象
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
-//collectionView的contentSize
- (CGSize)collectionViewContentSize
-#import 《UIKit/UIKit.h>
@protocol WaterPullLayoutDelegate
@required
- (CGSize)collectionView:(UICollectionView )collectionView layout:(UICollectionViewLayout )collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface WaterPullLayout : UICollectionViewLayout
/**
* 列数
*/
@property (nonatomic) NSInteger columnCount;
/**
* 距离上下左右的距离
*/
@property (nonatomic) UIEdgeInsets sectionInsets;
/**
* 两个cell的水平方向的空隙
*/
@property (nonatomic) CGFloat horizontalSpace;
/**
* 两个cell的垂直方向的空隙
*/
@property (nonatomic) CGFloat verticalSpace;
@end
#import "WaterPullLayout.h"
@interface WaterPullLayout ()
{
/**
* 保存每个cell的属性
*/
NSMutableArray *_itemAttributes;
/**
* 保存每列的高度
*/
NSMutableArray *_columnHeights;
}
@property (nonatomic, weak) id<WaterPullLayoutDelegate> delegate;
@end
@implementation WaterPullLayout
- (instancetype)init
{
self = [super init];
if (self)
{
//默认2列
_columnCount = 2;
_horizontalSpace = 10;
_verticalSpace = 10;
_sectionInsets = UIEdgeInsetsZero;
}
return self;
}
/**
* 返回高度最大的列的索引
*/
- (NSInteger)maxHeightColumnIndex
{
__block NSInteger index = 0;
__block CGFloat maxValue = 0;
[_columnHeights enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
{
//如果从数组里面取出的元素比现有最大值还大,这个元素就是最大值
if ([obj floatValue] > maxValue)
{
//替换最大值
maxValue = [obj floatValue];
//保存最大值的索引
index = idx;
}
}];
return index;
}
/**
* @return 返回高度最小的列的索引
*/
- (NSInteger)minHeightColumnIndex
{
__block NSInteger index = 0;
__block CGFloat minValue = MAXFLOAT;
[_columnHeights enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
{
//如果从数组里面取出的元素比现有最小值还小,这个元素就是最小值
if ([obj floatValue] < minValue)
{
//替换最小值
minValue = [obj floatValue];
//保存最小值的索引
index = idx;
}
}];
return index;
}
//对item布局,reloadData会触发
- (void)prepareLayout
{
[super prepareLayout];
self.delegate = (id<WaterPullLayoutDelegate>)self.collectionView.delegate;
//初始化数组
_itemAttributes = [NSMutableArray array];
_columnHeights = [NSMutableArray array];
//初始化默认高度
for (int i = 0; i < self.columnCount; i++)
{
//每列的高度初始化都是0
_columnHeights[i] = @(0);
}
//item的宽度 =(collectionView的宽 - 左边距 - 右边距 - item间的水平间隙 )/ 列数
CGFloat itemWidth = (self.collectionView.frame.size.width - self.sectionInsets.left - self.sectionInsets.right - (self.columnCount - 1)*self.horizontalSpace)/self.columnCount;
//计算每个item的位置坐标(只考虑一个组的情况)
//[self.collectionView numberOfItemsInSection:0]返回指定组的item个数
for (int i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++)
{
//获取item大小(调用collectionView的代理方法)
CGSize size = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
//item的高度
CGFloat itemHeight;
//item的x坐标
CGFloat xOffset;
//item的y坐标
CGFloat yOffset;
//现在图片的高度
/*
原始H X
---- = ----- ===> X = 原始H*现在W/原始W
原始W 现在W
*/
itemHeight = size.height * itemWidth / size.width;
//获取列的高度的最小值索引
NSInteger minIndex = [self minHeightColumnIndex];
NSLog(@"%ld",minIndex);
//item的x坐标 = 与左边间距 + 最小高度索引值*(item宽 + item间水平间隙)
xOffset = self.sectionInsets.left + minIndex*(itemWidth+self.horizontalSpace);
//item的y坐标 = 最小高度 + (item个数如果小于列数)?与顶部间距 :item间的垂直间隙
yOffset = [_columnHeights[minIndex] floatValue] + ((i < self.columnCount) ? self.sectionInsets.top : self.verticalSpace);
//item的frame
CGRect itemFrame = CGRectMake(xOffset, yOffset, itemWidth, itemHeight);
//属性
UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
attribute.frame = itemFrame;
//添加到数组中
[_itemAttributes addObject:attribute];
//修改当前列的高度
_columnHeights[minIndex] = @(CGRectGetMaxY(itemFrame));
}
}
/**
* 返回指定区域的cell的属性对象数组
*
* @param rect <#rect description#>
*
* @return <#return value description#>
*/
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return _itemAttributes;
}
/**
* 返回指定indexPath的item的属性对象
*
* @param indexPath <#indexPath description#>
*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
return _itemAttributes[indexPath.item];
}
/**
* collectionView的contentSize
*/
- (CGSize)collectionViewContentSize
{
//取最大值的索引
NSInteger maxIndex = [self maxHeightColumnIndex];
//返回collectionView的contentSize
return CGSizeMake(self.collectionView.frame.size.width, [_columnHeights[maxIndex] floatValue] + self.sectionInsets.bottom);
}
@end