//
|
// LMJVerticalFlowLayout.m
|
// 瀑布流完善接口
|
//
|
// Created by apple on 16/7/31.
|
// Copyright © 2016年 NJHu. All rights reserved.
|
//
|
|
#import "LMJVerticalFlowLayout.h"
|
#define LMJXX(x) floorf(x)
|
#define LMJXS(s) ceilf(s)
|
|
static const NSInteger LMJ_Columns_ = 3;
|
static const CGFloat LMJ_XMargin_ = 10;
|
static const CGFloat LMJ_YMargin_ = 10;
|
static const UIEdgeInsets LMJ_EdgeInsets_ = {20, 10, 10, 10};
|
|
@interface LMJVerticalFlowLayout()
|
|
/** 所有的cell的attrbts */
|
@property (nonatomic, strong) NSMutableArray<UICollectionViewLayoutAttributes *> *lmj_AtrbsArray;
|
|
/** 每一列的最后的高度 */
|
@property (nonatomic, strong) NSMutableArray<NSNumber *> *lmj_ColumnsHeightArray;
|
|
- (NSInteger)columns;
|
|
- (CGFloat)xMargin;
|
|
- (CGFloat)yMarginAtIndexPath:(NSIndexPath *)indexPath;
|
|
- (UIEdgeInsets)edgeInsets;
|
|
@end
|
|
@implementation LMJVerticalFlowLayout
|
|
/**
|
* 刷新布局的时候回重新调用
|
*/
|
- (void)prepareLayout
|
{
|
[super prepareLayout];
|
|
//如果重新刷新就需要移除之前存储的高度
|
[self.lmj_ColumnsHeightArray removeAllObjects];
|
|
//复赋值以顶部的高度, 并且根据列数
|
for (NSInteger i = 0; i < self.columns; i++) {
|
[self.lmj_ColumnsHeightArray addObject:@(self.edgeInsets.top)];
|
}
|
|
// 移除以前计算的cells的attrbs
|
[self.lmj_AtrbsArray removeAllObjects];
|
|
// 并且重新计算, 每个cell对应的atrbs, 保存到数组
|
for (NSInteger i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++)
|
{
|
[self.lmj_AtrbsArray addObject:[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]]];
|
}
|
|
}
|
|
|
/**
|
*在这里边所处每个cell对应的位置和大小
|
*/
|
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
|
{
|
UICollectionViewLayoutAttributes *atrbs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
|
CGFloat w = 1.0 * (self.collectionView.frame.size.width - self.edgeInsets.left - self.edgeInsets.right - self.xMargin * (self.columns - 1)) / self.columns;
|
|
w = LMJXX(w);
|
|
// 高度由外界决定, 外界必须实现这个方法
|
CGFloat h = [self.delegate waterflowLayout:self collectionView:self.collectionView heightForItemAtIndexPath:indexPath itemWidth:w];
|
|
// 拿到最后的高度最小的那一列, 假设第0列最小
|
__block NSInteger indexCol = 0;
|
__block CGFloat minColH = [self.lmj_ColumnsHeightArray[indexCol] doubleValue];
|
|
[self.lmj_ColumnsHeightArray enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
CGFloat colH = obj.floatValue;
|
if (minColH > colH) {
|
minColH = colH;
|
indexCol = idx;
|
}
|
}];
|
|
CGFloat x = self.edgeInsets.left + (self.xMargin + w) * indexCol;
|
|
CGFloat y = minColH + [self yMarginAtIndexPath:indexPath];
|
|
// 是第一行
|
if (minColH == self.edgeInsets.top) {
|
y = self.edgeInsets.top;
|
}
|
|
// 赋值frame
|
atrbs.frame = CGRectMake(x, y, w, h);
|
|
// 覆盖添加完后那一列;的最新高度
|
self.lmj_ColumnsHeightArray[indexCol] = @(CGRectGetMaxY(atrbs.frame));
|
|
return atrbs;
|
}
|
|
// layoutAttributesForElementsInRect
|
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
|
{
|
return self.lmj_AtrbsArray;
|
}
|
|
|
- (CGSize)collectionViewContentSize
|
{
|
CGFloat maxColH = [self.lmj_ColumnsHeightArray.firstObject doubleValue];
|
|
for (NSInteger i = 1; i < self.lmj_ColumnsHeightArray.count; i++)
|
{
|
CGFloat colH = [self.lmj_ColumnsHeightArray[i] doubleValue];
|
if(maxColH < colH)
|
{
|
maxColH = colH;
|
}
|
}
|
|
return CGSizeMake(self.collectionView.frame.size.width, maxColH + self.edgeInsets.bottom);
|
}
|
|
|
- (NSMutableArray *)lmj_AtrbsArray
|
{
|
if(_lmj_AtrbsArray == nil)
|
{
|
_lmj_AtrbsArray = [NSMutableArray array];
|
}
|
return _lmj_AtrbsArray;
|
}
|
|
- (NSMutableArray *)lmj_ColumnsHeightArray
|
{
|
if(_lmj_ColumnsHeightArray == nil)
|
{
|
_lmj_ColumnsHeightArray = [NSMutableArray array];
|
}
|
return _lmj_ColumnsHeightArray;
|
}
|
|
- (NSInteger)columns
|
{
|
if([self.delegate respondsToSelector:@selector(waterflowLayout:columnsInCollectionView:)])
|
{
|
return [self.delegate waterflowLayout:self columnsInCollectionView:self.collectionView];
|
}
|
else
|
{
|
return LMJ_Columns_;
|
}
|
}
|
|
- (CGFloat)xMargin
|
{
|
if([self.delegate respondsToSelector:@selector(waterflowLayout:columnsMarginInCollectionView:)])
|
{
|
return [self.delegate waterflowLayout:self columnsMarginInCollectionView:self.collectionView];
|
}
|
else
|
{
|
return LMJ_XMargin_;
|
}
|
}
|
|
- (CGFloat)yMarginAtIndexPath:(NSIndexPath *)indexPath
|
{
|
if([self.delegate respondsToSelector:@selector(waterflowLayout:collectionView:linesMarginForItemAtIndexPath:)])
|
{
|
return [self.delegate waterflowLayout:self collectionView:self.collectionView linesMarginForItemAtIndexPath:indexPath];
|
}else
|
{
|
return LMJ_YMargin_;
|
}
|
}
|
|
- (UIEdgeInsets)edgeInsets
|
{
|
if([self.delegate respondsToSelector:@selector(waterflowLayout:edgeInsetsInCollectionView:)])
|
{
|
return [self.delegate waterflowLayout:self edgeInsetsInCollectionView:self.collectionView];
|
}
|
else
|
{
|
return LMJ_EdgeInsets_;
|
}
|
}
|
|
- (id<LMJVerticalFlowLayoutDelegate>)delegate
|
{
|
return (id<LMJVerticalFlowLayoutDelegate>)self.collectionView.dataSource;
|
}
|
|
- (instancetype)initWithDelegate:(id<LMJVerticalFlowLayoutDelegate>)delegate
|
{
|
if (self = [super init]) {
|
}
|
return self;
|
}
|
|
|
+ (instancetype)flowLayoutWithDelegate:(id<LMJVerticalFlowLayoutDelegate>)delegate
|
{
|
return [[self alloc] initWithDelegate:delegate];
|
}
|
|
@end
|