【Flutter】自定义ListView开发记录(四)—— 关于ParentData的设想和分析与简单实践

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」。

前言

前面对hitTest方法进行了修改,以实现点击事件的处理;

但是肯定有人看出来了,这就是个治标不治本的方法,说白了,在整个SliverList流程中传递的数据并未修改,对于其他部分而言,它们还是根据数据,认为item按照ListView那种依次排列的方式进行的;

随着后续自定义ListView功能的增多,这部分肯定会造成困扰和误导;

那现在就来从数据源的角度进行一下修改;

评估

首先,先来确认下ParentData中的数据和其作用:

SliverList中parentData是 SliverMultiBoxAdaptorParentData ,在其中存放的是 index 和 keepAlive ;作用嘛,字面意思:

image.png

其父类放的就是经常使用的layoutOffset参数:

image.png

还有两个mixin,一个用来存放child链表关系:

image.png

另一个还是keepAlive相关……至于这个keepAlive和keptAlive有啥区别……好像没区别,get都给重写掉了……

image.png

现在要关注的是layoutOffset,起初我的想法是修改layoutOffset;但是layoutOffset所提供的作用不仅仅是为了表明位置,通过这个还能得知Item之间的相对位置关系;说白了就是能通过layoutOffset得知当前child前面多少多少是上一个child;

所以像现在这种,从lastChild往前遍历的方式上,能知道各个child之前的相对位置关系;还是挺有必要的~毕竟firstChild 并不一定会显示在ViewPort指定的可视范围内,如果所有child的layoutOffset都是实际在canvas上的位置,那么如何得知当前ScrollOffset对应哪些child呢;

纠结了一小段时间后,我发现,在源码中有这么个一个变量:paintOffset;比如说这种:

image.png

既然源码中有这种东西,或许追踪一下就知道怎么搞了

有个让我困惑的地方

首先还是先看注释:

image.png

按照注释说明,这东西正是我所需要的东西,用来体现child相对于parent位置的;

不过有个让我有点疑惑的东西,在注释中明确说明这东西最好用在仅有少量child的view上面;为啥这么说呢,讲道理设置个paintOffset,和设置layoutOffset没太大区别吧,无非到时候根据scrollOffset计算一下而已;

查看一下调用位置,确实正如注释中说明的那样,基本都是只持有一个child的那种View在使用这个parentData;

其具体调用位置也是performLayout这块;例如这样:

image.png

其中一个调用位置是这样的:

image.png

好像没啥太复杂的计算,或者延时操作啊,为啥指定持有少量child的View呢?

设计

我设想的方案同样是在performLayout 这块,在计算了各个item的 layoutOffset的同时, 结合情况,将paintOffset也计算出来,以目前计划实现的覆盖翻页为例:

image.png

那么需要做的事就明确了:

  • 提供设置一个新的ParentData,用于保存paintOffset;
  • 提供一个计算paintOffset的方法,提供给LayoutOffset;
  • 修改paint方法,改为根据paintOffset来绘制;
  • 修改hitTest方法,同样改为根据paintOffset来计算;

参考源码,ctrl + CV战士无所畏惧;

结尾

目前简单测试了下,并未发现什么性能损耗;所以注释中那段确实让我挺困惑的

Guess you like

Origin juejin.im/post/7031795764405731335