Flutter简单实现手写瀑布流 第三篇

1,126 阅读4分钟

经过长达一个月的期末考和短学期课程,终于有时间写第三篇了。做人不能太监。不多说,直接进入主题。

Flutter 简单实现手写瀑布流 第一篇 (juejin.cn)

Flutter简单实现手写瀑布流 第二篇 (juejin.cn)

三步走

一.重写performLayout

这个部分也就是对各个元素布局信息进行设定,分三个步骤。

1.初始时,元素的布局信息设定。

首先要执行其他功能逻辑,得保证元素充满一整行。这部分在源码(276-361,myrender.dart),这里得实现也很简单,向Element要子元素,满了就下一步,填充不满就进入输出布局信息,就return。

2.视窗上移,元素的布局信息设定。

视窗上移,也就是手指从上往下滑的过程。

这里不能随便找到顶部最短的卡片,然后获得其index-1对应的元素进行布局,这样会导致乱序,这里自己随便找张草稿纸画画就明白了。

如何实现?参考别人的思路,总结大概有两种,分页(没思路)或者记录下标,这里我选择了后者,即记录已经布局的元素对应哪个列,到时候布局就直接取。源码中叫layoutChildren(254行)。

视窗上移动的时候,得已经布局的元素中寻找顶部最短的元素,获取他们的上方坐标,用于新元素的布局。这里我创建了一个和纵轴元素个数长度相同的List(源码中叫 leadingChildContainer)来存放顶部元素。

需要布局的时候遍历这个表,获得,找到顶部最短元素,然后获得新元素进行布局,同时更新该表,这里来个动图演示一下。假设List存的下标为{[1,4],[2,5],[3,6]},而当前只布局到4,5,6三个元素。视窗上移时触发更新,找到最短的元素6,查表得上一个元素为3,于是找Element取下标为3的元素,同时更新leadingChildContainer(RenderBox)为[4,5,3]。

view_up.gif

布局停止的条件为该容器的 layoutOffset + paintExtentOf < scrollOffset的时候停止。源码(195行)

3.视窗下移,元素的布局信息设定。

视窗下移,也就是手指从下往上滑的过程。

这个时候得从已经布局的元素中寻找底部最短的元素,获取他的底部坐标,用于新元素的布局。同样,这里我创建了一个和纵轴元素个数长度相同的List(源码中叫 trailingChildContainer)来存放底部元素。

需要布局的时候只需从这个表遍历,找到底部最短元素,布局新元素,同时再次更新该表。这样找底部最短元素就没必要把所有元素遍历一边了,算是个小优化把。

这里上个动图演示一下。这里List的元素(RenderBox)由1,2,3变成了4,2,3。

view_down.gif

布局到List中最短元素的layoutOffset(相对于起始位置的偏移量)大于targetEndScrollOffset的时候停止,这部分的逻辑在(387-416)。

4.回收超出缓存范围的所有元素

这里的逻辑也很简单,两个步骤:回收上方元素和回收下方元素。具体实现也很简单,使用Element提供的removeChild回收的时候记得更新上述的两个Container。(源码144,164)

二.稍微改改paint方法

这边只需更改crossAxisDelta为对应的parentData即可,这个属性是控制绘制的位置,即距离屏幕左侧的偏移量。

 final double crossAxisDelta =
          (child.parentData as FlowSliverParentData).crossAxisPosition;

三.悄悄改改官方的SliverMultiBoxAdaptorElement

官方提供的新建元素方法createChild有保证元素是连续递增的要求。由于视窗上移的时候新生成的元素不一定是连续(但肯定是递增),于是这里进行重写,修改文件为silver.dart中的上述类内,代码就不贴在这里了,放在源码的render里面。

总结

仅供学习,因为是对官方源码的修改,写出了💩山(至少比之前的啥都没有好),能处理部分布局图片的情况源码在此。至于视窗那部分的源码还没磕过,如果真要以一个较为清晰的思路实现,还是得自己从Element和Widget慢慢搭积木,关于滑动,这只是冰山一角,上个最终效果,到此完结撒花。

play.gif