自定义瀑布流
//
// WaterPullLayout.m
// 瀑布流
//
// Created by qianfeng on 16/8/29.
// Copyright © 2016年 qianfeng. All rights reserved.
//
#import "WaterPullLayout.h"
#import "Model.h"
@interface WaterPullLayout ()
/**
* 保存每列的总高度
*/
@property (nonatomic, strong) NSMutableArray *columnHeightArray;
/**
* 保存cell详细信息
*/
@property (nonatomic, strong) NSMutableArray *itemAttributes;
@end
@implementation WaterPullLayout
-(instancetype)init
{
if (self = [super init]) {
/** 默认值 */
_column = 2; //列数
_sectionInsets = UIEdgeInsetsZero; //内边距
_lineSpacing = 10; //行间距
_interitemSpacing = 10; //列间距
}
return self;
}
#pragma mark - 自定义Layout四部曲
/**
* 1.布局cell,如果调用collectionView的reloaddata方法会触发该方法(相当于UItableView自定义控件中的LayoutSubViews)
*/
-(void)prepareLayout{
//初始化数组
_columnHeightArray = [NSMutableArray array];
_itemAttributes = [NSMutableArray array];
//添加默认值,每列高度默认是0
for (int i = 0; i < self.column; i++)
{
[_columnHeightArray addObject:@(0)];
}
/** 对每个cell位置进行计算 */
CGFloat xOffset;
CGFloat yOffset;
CGFloat itemWidth;
CGFloat itemHeight;
/** cell的宽度 */
itemWidth = (CGRectGetWidth(self.collectionView.frame) - self.sectionInsets.left - self.sectionInsets.right - _interitemSpacing * (_column - 1) ) / _column;
/** 组的个数 */
//[self.collectionView numberOfSections];
/** 每个组的cell的个数 */
NSInteger numberofItems = [self.collectionView numberOfItemsInSection:0];
/** 控制显示每个cell */
for (NSInteger i = 0; i < numberofItems; i ++) {
Model *model = self.datasourceArray[i];
/** 现在的高度 */
itemHeight = model.h * itemWidth / model.w;
/** 最小列的 index */
NSInteger minIndex = [self minIndexFromColumnHeightArray];
/** X */
xOffset = _sectionInsets.left + minIndex * (itemWidth + _interitemSpacing);
/** Y */
yOffset = (i < _column) ? _sectionInsets.top : ([_columnHeightArray[minIndex] floatValue] + _lineSpacing);
/** 创建item的attribute对象 */
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
attributes.frame = CGRectMake(xOffset, yOffset, itemWidth, itemHeight);
[self.itemAttributes addObject:attributes]; //保存item的属性信息
/** 修改数组中当前的最小高度 */
_columnHeightArray[minIndex] = @(CGRectGetMaxY(attributes.frame));
}
}
/**
* 2.返回指定范围的cell的布局的详细信息
*
* @param rect <#rect description#>
*
* @return <#return value description#>
*/
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
return self.itemAttributes;
}
/**
* 3.返回指定的cell的详细布局信息
*
* @param indexPath <#indexPath description#>
*
* @return <#return value description#>
*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
return self.itemAttributes[indexPath.item];
}
/**
* 4.重新计算当前滚动视图的contentSize
*
* @return <#return value description#>
*/
- (CGSize)collectionViewContentSize
{
//获取最大列的index
NSUInteger maxIndex = [self maxIndexFromColumnHeightArray];
return CGSizeMake(self.collectionView.frame.size.width, [_columnHeightArray[maxIndex] floatValue] + _sectionInsets.bottom);
}
#pragma mark - 普通Action
/**
* 求高度最小列的index
*/
-(NSInteger)minIndexFromColumnHeightArray
{
__block NSInteger minIndex = 0;
__block CGFloat min = MAXFLOAT;
[_columnHeightArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
/** 如果在当前数组有比当前数组还小的数,说明这个数就是最小值 */
if (min > [obj floatValue]) {
min = [obj floatValue];
minIndex = idx;
}
}];
return minIndex;
}
/**
* 返回高度最大的列index
*/
- (NSInteger)maxIndexFromColumnHeightArray
{
__block NSInteger maxIndex = 0;
//min=MAXFLOAT目的为了保证第一个值一定为最小值
__block CGFloat max = 0;
//遍历
[_columnHeightArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
//如果当前数组中有比当前最小值还小的数,说明当前这个数就是最小值
if (max < [obj floatValue])
{
//保存最小值
max = [obj floatValue];
//保存最下值的索引
maxIndex = idx;
}
}];
return maxIndex;
}
@end