一直以来对瀑布流的认识都是模棱两可的,知道这么个东西,一直没有认真的去做过研究,最近觉着是时候认真学习下,所以从网上down了一些demo,(我的习惯是喜欢先看别人代码,哪里不会的在查文档,哈哈)
瀑布流的使用没有什么难点,固定套路,我这里入手的是最常见,感觉最容易实现的一种方式,通过UICollectionView
完成,有时间在学习下其他的实现方式。<br > ok,开始 ......
1、 使用控件UICollectionView
,然后自定义一套流layout,继承自UICollectionViewLayout
,然后重写它的四个方法:
- (void)prepareLayout;
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
- (CGSize)collectionViewContentSize;
第一个方法完成一些初始化操作,不要漏掉super的调用;
第二个方法返回一个rect范围内的布局属性UICollectionViewLayoutAttributes
的数组;
第三个方法返回indexPath位置item的布局属性UICollectionViewLayoutAttributes
;
第四个方法返回视图可滚动范围;
2 、瀑布流的实现
简单一句话: 哪里短放哪里
首先,需要创建数组
/** 每列的高度数组*/
@property(nonatomic, strong)NSMutableArray *columnHeights;
关键代码的完成在第三步:
在这里完成每个item布局frame的更新,及columnHeight数组中最短列高度的更新
- 计算得到item的x, y, width, height,复赋值给Attributes对象
- 遍历columnHeights取出最短列,更新最短那列的值
__block NSUInteger minColumn = 0; //默认最短列为第0列
__block CGFloat minHeight = MAXFLOAT;
//计算当前item应该放在哪一列
[self.columnHeights enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { //遍历找出最小高度的列
CGFloat height = [obj doubleValue];
if (minHeight > height) {
minHeight = height;
minColumn = idx;
}
}];
//更新数组中的最短列高度
_columnHeights[minColumn] = @(y + height);
最后一步得到视图的contentSize大小,同样是遍历columnHeights数组,贴代码:
//得到最大列的高度
- (CGFloat)maxYWithColumnmHeightsArray:(NSArray *)array
{
__block CGFloat maxY = 0;
[_columnHeights enumerateObjectsUsingBlock:^(NSNumber *_Nonnull heightNumber, NSUInteger idx, BOOL * _Nonnull stop) {
if ([heightNumber doubleValue] > maxY) {
maxY = [heightNumber doubleValue];
}
}];
return maxY;
}
- (CGSize)collectionViewContentSize
{
return CGSizeMake(0, [self maxYWithColumnmHeightsArray:self.columnHeights] + [self edgeInsets].bottom);
}
写在最后:
没事喜欢研究好玩的东西,看源码,参考源码如下:(无先后,喜欢的可以共同学习)
github first ( 包含很多demo,不止瀑布流哦)
github second
github third