iOS--collectionView简单瀑布流的实现

2017-01-14 10:24:23来源:http://www.jianshu.com/p/d64658957ed5作者:黑白灰的绿i人点击

在看此篇文章之前,希望你已经有了一些对collectionView的理解。


一. 自定义layout

就像实现tableview的功能去自定义cell是差不多的,瀑布流的思路就是哪一列最短,就把下一个item放在哪一列。这样我们需要的属性就有,列间距,行间距,边距,还有保存item的attributes的数组。



1459930894315843.jpg
//总列数
@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;
//代理,用来计算item的高度
@property (nonatomic, weak) id<XRWaterfallLayoutDelegate> delegate;

接下来需要重写四个layout的系统方法


(1)- (void)prepareLayout 方法
//布局前的准备工作
- (void)prepareLayout {
[super prepareLayout];
//初始化字典,有几列就有几个键值对,key为列,value为列的最大y值,初始值为上内边距
for (int i = 0; i < self.columnCount; i++) {
self.maxYDic[@(i)] = @(self.sectionInset.top);
}
//根据collectionView获取总共有多少个item
NSInteger itemCount = [self.collectionView numberOfItemsInSection:0];
[self.attributesArray removeAllObjects];
//为每一个item创建一个attributes并存入数组
for (int i = 0; i < itemCount; i++) {
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[self.attributesArray addObject:attributes];
}
}

(2)- (CGSize)collectionViewContentSize方法
//计算collectionView的contentSize
- (CGSize)collectionViewContentSize {
__block NSNumber *maxIndex = @0;
//遍历字典,找出最长的那一列
[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {
if ([self.maxYDic[maxIndex] floatValue] < obj.floatValue) {
maxIndex = key;
}
}];
//collectionView的contentSize.height就等于最长列的最大y值+下内边距
return CGSizeMake(0, [self.maxYDic[maxIndex] floatValue] + self.sectionInset.bottom);
}

(3)- (UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath 方法

该方法则用来设置每个item的attributes,在这里,我们只需要简单的设置每个item的attributes.frame即可,首先我们必须得知collectionView的尺寸,然后我们根据collectionView的宽度,以及列数、各个间距来计算每个item的宽度


item的宽度 = (collectionView的宽度 - 内边距及列边距) / 列数
CGFloat collectionViewWidth = self.collectionView.frame.size.width;
//self.sectionInset.left:左边距 self.sectionInset.right:右边距
//(self.columnCount - 1) * columnSpacing:一行中所有的列边距
CGFloat itemWidth = (collectionViewWidth - self.sectionInset.left - self.sectionInset.right - (self.columnCount - 1) * self.columnSpacing) / self.columnCount;

item的y值就等于最短列的最大y值再加上行间距,x值就等于左边距 + (item宽度 + 列间距) * minColumn
//找出最短的那一列
__block NSNumber *minIndex = @0;
[self.maxYDic enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSNumber *obj, BOOL *stop) {
if ([self.maxYDic[minIndex] floatValue] > obj.floatValue) {
minIndex = key;
}
}];
//根据最短列的列数计算item的x值
CGFloat itemX = self.sectionInset.left + (self.columnSpacing + itemWidth) * minIndex.integerValue;
//item的y值 = 最短列的最大y值 + 行间距
CGFloat itemY = [self.maxYDic[minIndex] floatValue] + self.rowSpacing;

接下来便是item的高度,我们应该根据图片的原始尺寸以及计算出来的宽度,等比例缩放来计算高度,但是在layout类中,我们是拿不到图片的,因此我们可以定义一个block属性,或者代理,让外界来计算并返回给我们,我们需要将item的宽度以及indexPath传递给外界


@required
//计算item高度的代理方法,将item的高度与indexPath传递给外界
- (CGFloat)waterfallLayout:(XRWaterfallLayout *)waterfallLayout itemHeightForWidth:(CGFloat)itemWidth atIndexPath:(NSIndexPath *)indexPath;
@end

见详细代码

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台