前言
超简单的瀑布流实现,这里说一下笔者的思路,详细代码在这里
效果演示
实现思路
collectionView能实现各中吊炸天的布局,其精髓就在于UICollectionViewLayout,因此我们要自定义一个layout来继承系统的UICollectionViewLayout,所有工作都在这个类中进行
1.定义所需属性
瀑布流的思路就是,从上往下,那一列最短,就把下一个item放在哪一列,因此我们需要定义一个字典来记录每一列的最大y值
每一个item都有一个attributes,因此定义一个数组来保存每一个item的attributes
我们还必须知道有多少列以及列间距、行间距、section到collectionView的边距
1 2 3 4 5 6 7 8 9 10 11 12 |
//总列数 @property (nonatomic, assign) NSInteger columnCount; //列间距 @property (nonatomic, assign) NSInteger columnSpacing; //行间距 @property (nonatomic, assign) NSInteger rowSpacing; //section到collectionView的边距 @property (nonatomic, assign) UIEdgeInsets sectionInset; //保存每一列最大y值的数组 @property (nonatomic, strong) NSMutableDictionary *maxYDic; //保存每一个item的attributes的数组 @property (nonatomic, strong) NSMutableArray *attributesArray; |
2.重写系统方法
我们一共需要重写4个方法
a.- (void)prepareLayout
b.- (CGSize)collectionViewContentSize
c.- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
d.- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
– (void)prepareLayout 方法
布局前的一些准备工作都在这里进行
初始化字典,有几列就有几个键值对,key为第几列,value为列的最大y值,初始值为上内边距
1 2 3 |
for (int i = 0; i < self.columnCount; i++) { self.maxYDic[@(i)] = @(self.sectionInset.top); } |
创建每个item的attributes,并存入数组
1 2 3 4 5 6 7 8 |
//根据collectionView获取总共有多少个item NSInteger itemCount = [self.collectionView numberOfItemsInSection:0]; //为每一个item创建一个attributes并存入数组 for (int i = 0; i < itemCount; i++) { UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]]; [self.attributesArray addObject:attributes]; } |
– (CGSize)collectionViewContentSize 方法
用来计算collectionView的contentSize
一般瀑布流只能垂直滚动,不能水平滚动,因此contentSize.width = 0,我们只需要计算contentSize.height即可
从字典中找出最长列的最大y值,再加上下面的内边距,即为contentSize.height
1 2 3 4 5 6 7 8 9 10 11 12 13 |
- (CGSize)collectionViewContentSize { //假设第0列是最长的那列 __block NSNumber *maxIndex = @0; //遍历字典,找出最长的那一列 [self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) { //如果maxColumn列的最大y值小于obj,则让maxColumn等于obj所属的列 if ([self.maxYDic[maxIndex] floatValue] < obj.floatValue) { maxIndex = key; } }]; //collectionView的contentSize.height就等于最长列的最大y值+下内边距 return CGSizeMake(0, [self.maxYDic[maxIndex] floatValue] + self.sectionInset.bottom); } |
– (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 方法
该方法则用来设置每个item的attributes,在这里,我们只需要简单的设置每个item的attributes.frame即可
首先我们必须得知collectionView的尺寸,然后我们根据collectionView的宽度,以及列数、各个间距来计算每个item的宽度
item的宽度 = (collectionView的宽度 – 内边距及列边距) / 列数
1 2 3 4 5 |
CGFloat collectionViewWidth = self.collectionView.frame src="http://ww3.sinaimg.cn/mw690/0064cTs2gw1f2j5q5fszkg30ac0iihdu.gif" width="372" height="666">
实现思路
1.定义所需属性瀑布流的思路就是,从上往下,那一列最短,就把下一个item放在哪一列,因此我们需要定义一个字典来记录每一列的最大y值 每一个item都有一个attributes,因此定义一个数组来保存每一个item的attributes 我们还必须知道有多少列以及列间距、行间距、section到collectionView的边距
2.重写系统方法
– (void)prepareLayout 方法布局前的一些准备工作都在这里进行
创建每个item的attributes,并存入数组
– (CGSize)collectionViewContentSize 方法用来计算collectionView的contentSize 一般瀑布流只能垂直滚动,不能水平滚动,因此contentSize.width = 0,我们只需要计算contentSize.height即可 从字典中找出最长列的最大y值,再加上下面的内边距,即为contentSize.height
– (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 方法该方法则用来设置每个item的attributes,在这里,我们只需要简单的设置每个item的attributes.frame即可 首先我们必须得知collectionView的尺寸,然后我们根据collectionView的宽度,以及列数、各个间距来计算每个item的宽度 item的宽度 = (collectionView的宽度 – 内边距及列边距) / 列数
|