【Flutter】自定义ListView开发记录(一)——设计滑动效果的处理方式

1,193 阅读3分钟

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

前言

随着熊孩子拆组件之ListView系列的结束,装组件系列迎来了开始,从这篇开始我会记录实现自定义ListView过程中,自己的思考和实现方式;也方便以后整理代码~

那么首先从控制滑动方式这部分开始:

方案选择——滑动效果控制

首先看看需要的滑动效果:

  1. 仿真翻页 仿真翻页

在这个模式下,不需要任何滑动效果;唯一所做的事便是将item从上往下依次罗列;

  1. 覆盖翻页

覆盖翻页

覆盖翻页模式下,在上面仿真翻页效果基础上,仅仅将滑动效果应用于当前最顶层的可见页;

  1. 滚动翻页

image.png

滚动翻页效果跟ListView本身的效果没什么区别;

总结一下:

  • 在第一个模式下,position 的改变,仅仅是在一页翻过去的时候触发;
  • 在第二个模式下,position 的改变等同于现在的ListView,但是只应用于第一个可见页;
  • 在第三个模式下,等同于ListView,不需要任何处理;

现在具体分析设计一下:

在上一篇文章中,对于滑动效果的控制,我设想提出了三种实现方式:

  • 自定义ScrollerController;
  • 自定义ViewPort;
  • 自定义SliverList;

在ListView中,ScrollController 负责的部分就是控制ScrollPosition;ViewPort负责处理展示区域;SliverLit负责加载绘制内容,这三者之间是一个上级调用下级的关系;

虽说上级能调用下级,但是这三者其实并没有什么关联,比如说ScrollController只关心自己的Positiion,SliverList展示的什么,内容这么样并不关心,换句话说,ScrollController不知道SliverList的展示细节,除非它提供到ScrollPosition中;

这样的话,ScrollController是无法得知SliverList的展示状态;ViewPort也同理,仅仅通过position的修改,是无法区分当前position是在第几页,偏移量多少,让position中的pixels生效有意义的地方,就是SliverList;

所以修改方式,应该是自定义SliverList;

具体实现方式:

这里就参考之前的中秋投稿,说白了,对SliverList的RenderObject层进行修改:

在中秋投稿那次,我重写了RenderSliverList 的 paint方法,在原本的SliverList中,是这么规定绘制child的:

image.png

可以看到,其实paint方法中才是真正去计算 child 位置的地方,先看childMainAxisPosition方法:

image.png

image.png

在这里会去计算主轴的位置,依据便是之前在layout方法中,遍历child并给其parentData设置的layoutOffset参数,并减去当前已经滑动的距离;

交叉轴这块,则直接返回0

image.png

自此就算出了具体的相对位置,之后就传给paint方法进行绘制;

之后就是获取下一个child,再次循环上述流程;

而如果要实现上面提到的效果,要做的事也比较简单:

  • 如果是效果1,那么一直将所有child的绘制位置改为0即可;
  • 如果是效果2,那么仅仅在第一个child上加上scrollOffset的偏移量计算即可;

当然,由于绘制顺序的关系,获取child要先从lastChild获取,并不断取之前的child,直到第一个child;

如果再结合自定义路径,加入变化Item的能力,那就要引入设想的LayoutManager的能力;

在此先将这部分逻辑抽离,等LayoutManager调用使用;

结语:

这个滑动效果实现方式非常简单,麻烦的地方反而是如何将自定义SliverList的接进去~

下一步看下对Element层面的改造,暴露RenderObject 的layout、paint方法出去