|
@@ -1,225 +1,173 @@
|
|
|
//
|
|
|
// WaterFallLayout.m
|
|
|
-// WateFallLayoutTest
|
|
|
+// layout
|
|
|
//
|
|
|
-// Created by 刘梦桦 on 2017/5/18.
|
|
|
-// Copyright © 2017年 . All rights reserved.
|
|
|
+// Created by meterscao on 16/5/23.
|
|
|
+// Copyright © 2016年 meters. All rights reserved.
|
|
|
//
|
|
|
|
|
|
#import "WaterFallLayout.h"
|
|
|
|
|
|
-/** 默认的列数 */
|
|
|
-static const CGFloat DefaultColunmCount = 2;
|
|
|
-/** 每一列之间的间距 */
|
|
|
-static const CGFloat DefaultColunmMargin = 10;
|
|
|
+@interface WaterFallLayout ()
|
|
|
|
|
|
-/** 每一行之间的间距 */
|
|
|
-static const CGFloat DefaultRowMargin = 10;
|
|
|
+@property (nonatomic) UIEdgeInsets contentInsets;
|
|
|
|
|
|
-/** 内边距 */
|
|
|
-static const UIEdgeInsets DefaultEdgeInsets = {10,10,10,10};
|
|
|
+@property (nonatomic) int columnCounts;
|
|
|
+@property (nonatomic) CGFloat columnWidth;
|
|
|
|
|
|
+@property (nonatomic) CGFloat gapHorizontal;
|
|
|
+@property (nonatomic) CGFloat gapVertical;
|
|
|
|
|
|
-@interface WaterFallLayout()
|
|
|
-/** 存放所有的布局属性 */
|
|
|
-@property (nonatomic, strong) NSMutableArray * attrsArr;
|
|
|
-/** 存放所有列的当前高度 */
|
|
|
-@property (nonatomic, strong) NSMutableArray *columnHeights;
|
|
|
-/** 内容的高度 */
|
|
|
-@property (nonatomic, assign) CGFloat contentHeight;
|
|
|
+@property (nonatomic) NSMutableArray *YArray;
|
|
|
|
|
|
-- (NSUInteger)colunmCount;
|
|
|
-- (CGFloat)columnMargin;
|
|
|
-- (CGFloat)rowMargin;
|
|
|
-- (UIEdgeInsets)edgeInsets;
|
|
|
+@property (nonatomic) CGFloat containerWidth;
|
|
|
|
|
|
@end
|
|
|
|
|
|
@implementation WaterFallLayout
|
|
|
|
|
|
+#pragma mark - 基本实现
|
|
|
+- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
|
|
|
+ return YES;
|
|
|
+}
|
|
|
|
|
|
|
|
|
-#pragma mark 懒加载
|
|
|
-- (NSMutableArray *)attrsArr{
|
|
|
- if (!_attrsArr) {
|
|
|
- _attrsArr = [NSMutableArray array];
|
|
|
- }
|
|
|
+-(void)prepareLayout{
|
|
|
|
|
|
- return _attrsArr;
|
|
|
-}
|
|
|
-
|
|
|
-- (NSMutableArray *)columnHeights{
|
|
|
- if (!_columnHeights) {
|
|
|
- _columnHeights = [NSMutableArray array];
|
|
|
+ [super prepareLayout];
|
|
|
+
|
|
|
+ [self initConfit];
|
|
|
+
|
|
|
+
|
|
|
+ // 计算出各个尺寸
|
|
|
+ self.containerWidth = self.collectionView.frame.size.width ;
|
|
|
+
|
|
|
+ self.YArray = [[NSMutableArray alloc]initWithCapacity:self.columnCounts];
|
|
|
+
|
|
|
+ for (int index = 0; index < self.columnCounts; index ++) {
|
|
|
+ self.YArray[index] = @(self.contentInsets.top);
|
|
|
}
|
|
|
|
|
|
- return _columnHeights;
|
|
|
+ self.columnWidth = ( self.containerWidth - self.contentInsets.left - self.contentInsets.right - self.gapHorizontal * (self.columnCounts - 1)) / self.columnCounts;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
-#pragma mark - 数据处理
|
|
|
-/**
|
|
|
- * 列数
|
|
|
- */
|
|
|
-- (NSUInteger)colunmCount{
|
|
|
+// 返回当前瀑布流视图整个内容区域的高度
|
|
|
+-(CGSize)collectionViewContentSize{
|
|
|
|
|
|
- if ([self.delegate respondsToSelector:@selector(columnCountInWaterFallLayout:)]) {
|
|
|
- return [self.delegate columnCountInWaterFallLayout:self];
|
|
|
- }else{
|
|
|
- return DefaultColunmCount;
|
|
|
- }
|
|
|
+ return CGSizeMake(self.containerWidth,
|
|
|
+ [self.YArray[[self indexOfMaxY]] floatValue] - self.gapVertical + self.contentInsets.bottom);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 列间距
|
|
|
- */
|
|
|
-- (CGFloat)columnMargin{
|
|
|
- if ([self.delegate respondsToSelector:@selector(columnMarginInWaterFallLayout:)]) {
|
|
|
- return [self.delegate columnMarginInWaterFallLayout:self];
|
|
|
- }else{
|
|
|
- return DefaultColunmMargin;
|
|
|
- }
|
|
|
-}
|
|
|
+-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
|
|
|
|
|
|
-/**
|
|
|
- * 行间距
|
|
|
- */
|
|
|
-- (CGFloat)rowMargin{
|
|
|
- if ([self.delegate respondsToSelector:@selector(rowMarginInWaterFallLayout:)]) {
|
|
|
- return [self.delegate rowMarginInWaterFallLayout:self];
|
|
|
- }else{
|
|
|
- return DefaultRowMargin;
|
|
|
+ NSMutableArray *layoutAttibutes = [[NSMutableArray alloc]init];
|
|
|
+
|
|
|
+ for (int i = 0 ; i < [self.collectionView numberOfItemsInSection:0]; i ++) {
|
|
|
+ NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
|
|
|
+ [layoutAttibutes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+ return layoutAttibutes;
|
|
|
|
|
|
-/**
|
|
|
- * item的内边距
|
|
|
- */
|
|
|
-- (UIEdgeInsets)edgeInsets{
|
|
|
- if ([self.delegate respondsToSelector:@selector(edgeInsetdInWaterFallLayout:)]) {
|
|
|
- return [self.delegate edgeInsetdInWaterFallLayout:self];
|
|
|
- }else{
|
|
|
- return DefaultEdgeInsets;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * 初始化
|
|
|
- */
|
|
|
-- (void)prepareLayout{
|
|
|
+-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
|
|
|
|
|
|
- [super prepareLayout];
|
|
|
+ CGFloat x,y,itemWidth,itemHeight;
|
|
|
|
|
|
- self.contentHeight = 0;
|
|
|
+ int index = [self indexOfMinY];
|
|
|
|
|
|
- // 清楚之前计算的所有高度
|
|
|
- [self.columnHeights removeAllObjects];
|
|
|
+ x = [self XOfColumn:index];
|
|
|
+ y = [self.YArray[index] floatValue];
|
|
|
+ itemWidth = self.columnWidth;
|
|
|
+ itemHeight = [self.delegate collectionView:self.collectionView heightOfItemAtIndexPath:indexPath];
|
|
|
|
|
|
- // 设置每一列默认的高度
|
|
|
- for (NSInteger i = 0; i < DefaultColunmCount ; i ++) {
|
|
|
- [self.columnHeights addObject:@(DefaultEdgeInsets.top)];
|
|
|
+ // 更新插入新的item之后,当前列的底部纵坐标
|
|
|
+ self.YArray[index] = @(y + itemHeight + self.gapHorizontal);
|
|
|
+
|
|
|
+ UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
|
|
+ attributes.frame = CGRectMake(x, y, itemWidth, itemHeight);
|
|
|
+ return attributes;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark - 初始化
|
|
|
+-(void)initConfit{
|
|
|
+ // 初始化各项配置
|
|
|
+ if ([self.delegate respondsToSelector:@selector(contentInsetsForCollectionView:)]) {
|
|
|
+ self.contentInsets = [self.delegate contentInsetsForCollectionView:self.collectionView];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ self.contentInsets = UIEdgeInsetsMake(10, 10, 10, 10);
|
|
|
}
|
|
|
|
|
|
|
|
|
- // 清楚之前所有的布局属性
|
|
|
- [self.attrsArr removeAllObjects];
|
|
|
-
|
|
|
- // 开始创建每一个cell对应的布局属性
|
|
|
- NSInteger count = [self.collectionView numberOfItemsInSection:0];
|
|
|
+ if ([self.delegate respondsToSelector:@selector(horizontalGapForCollectionView:)]) {
|
|
|
+ self.gapHorizontal = [self.delegate horizontalGapForCollectionView:self.collectionView];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ self.gapHorizontal = 10.f;
|
|
|
+ }
|
|
|
|
|
|
- for (int i = 0; i < count; i++) {
|
|
|
-
|
|
|
- // 创建位置
|
|
|
- NSIndexPath * indexPath = [NSIndexPath indexPathForItem:i inSection:0];
|
|
|
-
|
|
|
- // 获取indexPath位置上cell对应的布局属性
|
|
|
- UICollectionViewLayoutAttributes * attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
|
|
|
-
|
|
|
- [self.attrsArr addObject:attrs];
|
|
|
+ if ([self.delegate respondsToSelector:@selector(verticalGapForCollectionView:)]) {
|
|
|
+ self.gapVertical = [self.delegate verticalGapForCollectionView:self.collectionView];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ self.gapVertical = 10.f;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ if ([self.delegate respondsToSelector:@selector(columenCountsForCollectionView:)]) {
|
|
|
+ self.columnCounts = [self.delegate columenCountsForCollectionView:self.collectionView];
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ self.columnCounts = 2;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
+#pragma mark - 工具函数
|
|
|
|
|
|
-/**
|
|
|
- * 返回indexPath位置cell对应的布局属性
|
|
|
- */
|
|
|
-- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
|
|
|
-
|
|
|
- // 创建布局属性
|
|
|
- UICollectionViewLayoutAttributes * attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
|
|
-
|
|
|
- //collectionView的宽度
|
|
|
- CGFloat collectionViewW = self.collectionView.frame.size.width;
|
|
|
+// 计算当前列的横坐标
|
|
|
+-(CGFloat)XOfColumn:(int)index{
|
|
|
|
|
|
- // 设置布局属性的frame
|
|
|
+ return self.contentInsets.left + (self.columnWidth + self.gapHorizontal)*index;
|
|
|
|
|
|
- CGFloat cellW = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.colunmCount - 1) * self.columnMargin) / self.colunmCount;
|
|
|
- CGFloat cellH = [self.delegate waterFallLayout:self heightForItemAtIndexPath:indexPath.item itemWidth:cellW];
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
+// 筛选出当前纵坐标最小的列,用以确定新的item插入到哪一列
|
|
|
+-(int)indexOfMinY{
|
|
|
|
|
|
- // 找出最短的那一列
|
|
|
- NSInteger destColumn = 0;
|
|
|
- CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
|
|
|
+ int resultIndex = 0;
|
|
|
+ CGFloat minY = [self.YArray[0] floatValue];
|
|
|
|
|
|
- for (int i = 1; i < DefaultColunmCount; i++) {
|
|
|
-
|
|
|
- // 取得第i列的高度
|
|
|
- CGFloat columnHeight = [self.columnHeights[i] doubleValue];
|
|
|
-
|
|
|
- if (minColumnHeight > columnHeight) {
|
|
|
- minColumnHeight = columnHeight;
|
|
|
- destColumn = i;
|
|
|
+ for (int index = 1; index < self.columnCounts; index ++ ) {
|
|
|
+ if([self.YArray[index] floatValue] < minY ){
|
|
|
+ minY = [self.YArray[index] floatValue];
|
|
|
+ resultIndex = index;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- CGFloat cellX = self.edgeInsets.left + destColumn * (cellW + self.columnMargin);
|
|
|
- CGFloat cellY = minColumnHeight;
|
|
|
- if (cellY != self.edgeInsets.top) {
|
|
|
-
|
|
|
- cellY += self.rowMargin;
|
|
|
- }
|
|
|
-
|
|
|
- attrs.frame = CGRectMake(cellX, cellY, cellW, cellH);
|
|
|
-
|
|
|
- // 更新最短那一列的高度
|
|
|
- self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));
|
|
|
-
|
|
|
- // 记录内容的高度 - 即最长那一列的高度
|
|
|
- CGFloat maxColumnHeight = [self.columnHeights[destColumn] doubleValue];
|
|
|
- if (self.contentHeight < maxColumnHeight) {
|
|
|
- self.contentHeight = maxColumnHeight;
|
|
|
- }
|
|
|
-
|
|
|
- return attrs;
|
|
|
+ return resultIndex;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 决定cell的高度
|
|
|
- */
|
|
|
-- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
|
|
|
-
|
|
|
- return self.attrsArr;
|
|
|
-}
|
|
|
|
|
|
-/**
|
|
|
- * 内容的高度
|
|
|
- */
|
|
|
-- (CGSize)collectionViewContentSize{
|
|
|
-
|
|
|
-// CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
|
|
|
-// for (int i = 0; i < DefaultColunmCount; i++) {
|
|
|
-//
|
|
|
-// // 取得第i列的高度
|
|
|
-// CGFloat columnHeight = [self.columnHeights[i] doubleValue];
|
|
|
-//
|
|
|
-// if (maxColumnHeight < columnHeight) {
|
|
|
-// maxColumnHeight = columnHeight;
|
|
|
-// }
|
|
|
-//
|
|
|
-// }
|
|
|
+// 筛选出当前纵坐标最大的列,用以确定整个视图的高度
|
|
|
+-(int)indexOfMaxY{
|
|
|
+ int resultIndex = 0;
|
|
|
+ CGFloat maxY = [self.YArray[0] floatValue];
|
|
|
|
|
|
- return CGSizeMake(0, self.contentHeight + self.edgeInsets.bottom);
|
|
|
+ for (int index = 1; index < self.columnCounts; index ++ ) {
|
|
|
+ if([self.YArray[index] floatValue] > maxY ){
|
|
|
+ maxY = [self.YArray[index] floatValue];
|
|
|
+ resultIndex = index;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return resultIndex;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
@end
|