瀑布流
2016-04-20 15:23
483 查看
之前师父让我写瀑布流,当时虽然照葫芦画瓢写出来了一个,但是并没有完全理解,今天再重新看了一遍,基本都弄懂了,记录一下。
可能有的人会问:“什么是瀑布流?”
就是比如你在淘宝上买东西时,各种商品参差不齐的展现出来。
还是老规矩,先举个栗子。这是不用瀑布流的效果:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202005/07/dec987587ba72f4b29dbb75e1bcfd211)
可以看到,左边的 cell 中的内容有两行,但是右边的 cell 中的内容只有一行,所以就会导致右边的 cell 的上面和下面多出来一段距离,这样就会显得很丑。
然后我们来看看用了瀑布流的效果:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202005/07/a54e526264d9f8a4d9adeaa1c41418c7)
一看就懂了吧。
然后我们来说说这是怎么实现的。为了更直观,我们先不说代码,直接看效果图,代码后面再说。
首先,找到高度最小的那一列。
这是什么意思呢?例如上面的图中,共有两列。我再举一个三列的栗子吧:
假设是三列的,现在已经有了三个 cell(编号为1、2、3),如图所示(手绘,丑就丑吧):
(PS:我用的mac,用的是一个叫 Paintbrush 的软件,功能类似 windows 里的画图)
![](https://oscdn.geek-share.com/Uploads/Images/Content/202005/07/3f9efec0e46dd1b35e847fabc49b1c9b)
那么高度最小的一列就是中间那列。
然后,计算当前 cell(此时是第四个 cell)的 frame,然后把这个 cell 加进高度最小的那一列(此时是第二列),结果如图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202005/07/aba19576bd4bfa522a0a5a0b9e678942)
同理,轮到第五个 cell 的时候,高度最小的一列就是第一列了,那么就把第五个 cell 放在第一列,以此类推。
没了,就这么简单。用一句话概括瀑布流,就是我们自己布置每一个 cell,让它们错落有致。
下面我们就来具体说说实现过程。
首先,怎么找到高度最小的一列?
定义一个可变数组 cellHeightArray,用于存放每一列的高度。
然后,怎么计算当前 cell 的 frame?
定义一个代理,遵守 UICollectionViewFlowLayoutDelegate 协议。
然后通过协议获取 cell 的间隙和大小:
然后更改 cell 的 frame,存进字典中。别忘了更新当前列的高度:
返回 cell 布局信息的时候有一个优化。如果一次性返回所有 cell 的布局信息的话可能会导致性能很差,比如说有很多图片的时候。其实我们只需要返回当前能看到的 cell 就行了。当下滑或者上滑的时候再返回其它 cell。
那具体该怎么做呢?只要判断当前的 cell 是否包含在指定的 rect 内即可,是的话就存在数组中:
layoutAttributesForItemAtIndexPath: 方法如下:
最后要返回 contentSize,遍历存放列高的数组,找到最高列的高度即可:
OK,大功告成!最后只要在设置 collectionView 的 flowLayout 的时候,把它设置成我们自定义的 flowLayout 就行了:
完整源码见我的github:https://github.com/963239327/UICollectionViewFlowLayout- 别忘了点击右上角的
star 哦
可能有的人会问:“什么是瀑布流?”
就是比如你在淘宝上买东西时,各种商品参差不齐的展现出来。
还是老规矩,先举个栗子。这是不用瀑布流的效果:
可以看到,左边的 cell 中的内容有两行,但是右边的 cell 中的内容只有一行,所以就会导致右边的 cell 的上面和下面多出来一段距离,这样就会显得很丑。
然后我们来看看用了瀑布流的效果:
一看就懂了吧。
然后我们来说说这是怎么实现的。为了更直观,我们先不说代码,直接看效果图,代码后面再说。
首先,找到高度最小的那一列。
这是什么意思呢?例如上面的图中,共有两列。我再举一个三列的栗子吧:
假设是三列的,现在已经有了三个 cell(编号为1、2、3),如图所示(手绘,丑就丑吧):
(PS:我用的mac,用的是一个叫 Paintbrush 的软件,功能类似 windows 里的画图)
那么高度最小的一列就是中间那列。
然后,计算当前 cell(此时是第四个 cell)的 frame,然后把这个 cell 加进高度最小的那一列(此时是第二列),结果如图:
同理,轮到第五个 cell 的时候,高度最小的一列就是第一列了,那么就把第五个 cell 放在第一列,以此类推。
没了,就这么简单。用一句话概括瀑布流,就是我们自己布置每一个 cell,让它们错落有致。
下面我们就来具体说说实现过程。
首先,怎么找到高度最小的一列?
定义一个可变数组 cellHeightArray,用于存放每一列的高度。
NSInteger column = 0; float shortHeight = [[_cellHeightArray objectAtIndex:column] floatValue]; //找出高度最小的列 for (int i = 0; i < _cellHeightArray.count; i++) { float height = [[_cellHeightArray objectAtIndex:i] floatValue]; if (height < shortHeight) { shortHeight = height; column = i; } }column 和 shortHeight 是临时变量,用来记录高度最小的列的编号和高度。
然后,怎么计算当前 cell 的 frame?
定义一个代理,遵守 UICollectionViewFlowLayoutDelegate 协议。
@property (nonatomic, assign) id<UICollectionViewDelegateFlowLayout> delegate;
然后通过协议获取 cell 的间隙和大小:
// 通过协议获得cell的间隙 UIEdgeInsets edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:indexPath.row]; // 通过协议获得cell的大小 CGSize itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
然后更改 cell 的 frame,存进字典中。别忘了更新当前列的高度:
float top = [[_cellHeightArray objectAtIndex:column] floatValue]; //确定cell的frame CGRect frame = CGRectMake(edgeInsets.left + column * (edgeInsets.left + itemSize.width), top + edgeInsets.top, itemSize.width, itemSize.height); //更新列高 [_cellHeightArray replaceObjectAtIndex:column withObject:[NSNumber numberWithFloat:top + edgeInsets.top + itemSize.height]]; //每个cell的frame对应一个indexPath,放入字典中 [_cellAttributeDict setObject:NSStringFromCGRect(frame) forKey:indexPath];
返回 cell 布局信息的时候有一个优化。如果一次性返回所有 cell 的布局信息的话可能会导致性能很差,比如说有很多图片的时候。其实我们只需要返回当前能看到的 cell 就行了。当下滑或者上滑的时候再返回其它 cell。
那具体该怎么做呢?只要判断当前的 cell 是否包含在指定的 rect 内即可,是的话就存在数组中:
//返回cell的布局信息,如果忽略传入的rect一次性将所有的cell布局信息返回,图片过多时性能会很差 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSMutableArray *muArr = [NSMutableArray array]; for (NSIndexPath *indexPath in _cellAttributeDict) { CGRect cellRect = CGRectFromString(_cellAttributeDict[indexPath]); if (CGRectIntersectsRect(cellRect, rect)) { UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath]; [muArr addObject:attributes]; } } return muArr; }
layoutAttributesForItemAtIndexPath: 方法如下:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attributes.frame = CGRectFromString(_cellAttributeDict[indexPath]); return attributes; }
最后要返回 contentSize,遍历存放列高的数组,找到最高列的高度即可:
- (CGSize)collectionViewContentSize { CGSize size = self.collectionView.frame.size; float maxHeight = 0; // 查找最高的列的高度 for (int i = 0; i < _cellHeightArray.count; i++) { float colHeight = [[_cellHeightArray objectAtIndex:i] floatValue]; if (colHeight > maxHeight) { maxHeight = colHeight; } } size.height = maxHeight; return size; }
OK,大功告成!最后只要在设置 collectionView 的 flowLayout 的时候,把它设置成我们自定义的 flowLayout 就行了:
LZNCollectionViewFlowLayout *flow = [[LZNCollectionViewFlowLayout alloc] init]; flow.delegate = self; _myCollectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:flow];
完整源码见我的github:https://github.com/963239327/UICollectionViewFlowLayout- 别忘了点击右上角的
star 哦
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 异步加载技术实现当滚动条到最底部的瀑布流效果
- 基于JavaScript实现瀑布流布局
- 基于JavaScript实现瀑布流效果(循环渐近)
- 原生JS实现美图瀑布流布局赏析
- 详解javascript实现瀑布流列式布局
- javascript瀑布流式图片懒加载实例
- javascript实现仿百度图片的瀑布流加载效果
- avalonjs制作响应式瀑布流特效
- javascript实现瀑布流加载图片原理
- jquery 插件实现瀑布流图片展示实例
- jquery代码实现简单的随机图片瀑布流效果
- 深入探秘jquery瀑布流的实现
- JavaScript实现图片自动加载的瀑布流效果