// // 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 *lmj_AtrbsArray; /** 每一列的最后的高度 */ @property (nonatomic, strong) NSMutableArray *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 *)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)delegate { return (id)self.collectionView.dataSource; } - (instancetype)initWithDelegate:(id)delegate { if (self = [super init]) { } return self; } + (instancetype)flowLayoutWithDelegate:(id)delegate { return [[self alloc] initWithDelegate:delegate]; } @end