做项目的时候遇到一些界面需要的布局非常自由而网上搜了一些开源的代码都没找到一个理想的,于是自己就准备写一种比较理想的布局,一种可以像系统的UICollectionViewFlowLayout一样从左到右的流式布局,又能像CHTCollectionViewWaterfallLayout一样的从上到下瀑布流布局,并且完全能兼容这两种布局的能力,想到就做(就算不能一步到位也可以慢慢实现直到解决问题)。

这里首先来看一下UICollectionViewFlowLayout的一种布局情况
assets/UICollectionViewFlowLayout.gif
可以看到这么多空白位置多浪费,这也是我想写一个布局的原因之一(浪费可耻)

然后在看一个网上写的比较好的布局CHTCollectionViewWaterfallLayout显示情况
assets/CHTCollectionViewWaterfallLayout.gif
虽然不浪费空间了,但是有一个致命的问题(宽度都是一样的),对于一个追求完美的程序员来所这完全是无法容忍的(作者不要打我。我这里只是说不够理想,并不是说这个布局不够好,这个布局是我在GitHub上见过写得最好的了)...

下面看一个理想中的布局
assets/WYWaterFlowLayout.gif
为了这个理想布局我开始了撸代码。

这里首先打下草稿定下几点实现思路(这里就不讲layout定制的基础教程了,网上一大片)
1.布局方向采用从上到下从左到右(就类似下的雨留到河流里面的继续往海里流一样)
2.所有复杂页面的布局都能通过业务层给出适当的size实现
3.完全可以像系统的UICollectionViewFlowLayout一样使用,这里接口几乎跟系统API一毛一样
4.理想状态是性能要高

最开始一直没想到一个好的办法计算这种从上到下从左到右的布局,直到有一天撸代码的时候使用到了NSIndexSet,突然灵光一闪想到了这个NSIndexSet完全可以解决这种理想的layout的布局计算。于是在我撸啊撸的情况下总算撸出来了一个初版。为什么叫初版呢? 是因为虽然功能是实现了,但是细节和性能还有待提升!这需要后续持续完善。

下面给出初版的性能测试对比(测试设备:iPhone6,数据量:10万)

function preparLayout layoutAttributesForElementsInRect 内存使用(1条数据的时候4.9MB)
UICollectionViewFlowLayout 258.518 ms 1.100 ms 20.9 MB
CHTCollectionViewWaterfallLayout 864.026 ms 1.613 ms 35.6 MB
WYWaterFlowLayout 2292.417 ms 2.088 ms 51.6 MB

当然10万数据有点大 这里给个1万数据的测试

function preparLayout layoutAttributesForElementsInRect 内存使用
UICollectionViewFlowLayout 25.087 ms 0.614 ms 6.7 MB
CHTCollectionViewWaterfallLayout 80.257 ms 0.271 ms 8.8 MB
WYWaterFlowLayout 160.849 ms 0.209 ms 10.3 MB

 看这个测试数据勉强还能接受,除了布局时间长一点,滑动性能还可以,基本算可以使用了。但是对于一个励志要改变世界的程序员来说必须得追求极限,这里跟CHTCollectionViewWaterfallLayout对比性能相差了将近一倍,性能瓶颈主要在下面这个函数,因为10万数据的测试1645.468ms里面有1200ms都是这个函数消耗的,通过优化这个函数可以大幅度提升性能。

- (CGRect)willAddItemWithSize:(CGSize)size maxWidth:(CGFloat)maxWidth maxTop:(CGFloat *)p_top withSpaces:(NSMutableArray<WYSpaceIndexSet *> *)emptySpaces

这个函数主要是传入一个需要布局的item的size、布局所在的宽度和空白位置记录数据,返回这个item的frame和当前布局到的最大y坐标,这个函数也是这个布局最核心的函数了,函数主要是做了三件事
1.根据已有空位记录找到要插入的item可以放的位置
2.更新空白位置记录,比插入item低的空位被它占用,比插入item高的会占用当前的空位
3.把空位记录按低到高左到右排序

生活中一切目标都能通过解决N个问题实现 ---- 刚想出来的。 这里争取只遍历一遍就完成查找排序更新,想到就做。首先这里通过优化排序算法,把2292.417ms的运算时间降低到了1220.73ms;然后通过简化数据结构把运算时间降低到1000ms左右,勉强可用了。

下面附上简化后的性能测试数据(测试设备:iPhone6,数据量:10万)

function preparLayout layoutAttributesForElementsInRect 内存使用(1条数据的时候4.9MB)
UICollectionViewFlowLayout 258.518 ms 1.100 ms 20.9 MB
CHTCollectionViewWaterfallLayout 864.026 ms 1.613 ms 35.6 MB
WYWaterFlowLayout 1076.112 ms 1.776 ms 50.4 MB

当然10万数据有点大 这里给个1万数据的测试

function preparLayout layoutAttributesForElementsInRect 内存使用
UICollectionViewFlowLayout 25.087 ms 0.614 ms 6.7 MB
CHTCollectionViewWaterfallLayout 80.257 ms 0.271 ms 8.8 MB
WYWaterFlowLayout 98.604 ms 0.246 ms 10.4 MB

这里跟CHTCollectionViewWaterfallLayout的性能已经很接近了,在复杂度提高的情况下能把性能控制得差不多这里也算基本满意了。 后续可以继续优化这里的计算,以及像素点对齐。 Demo

License

WYWaterFlowLayout is available under the MIT license. See the LICENSE file for more info.

Copyright © 413132340@qq.com 2020 all right reserved,powered by Gitbook该文章修订时间: 2020-11-30 07:49:29

results matching ""

    No results matching ""