「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战」。
前言
随着熊孩子拆组件之ListView系列的结束,装组件系列迎来了开始,从这篇开始我会记录实现自定义ListView过程中,自己的思考和实现方式;也方便以后整理代码~
那么首先从控制滑动方式这部分开始:
方案选择——滑动效果控制
首先看看需要的滑动效果:
- 仿真翻页
在这个模式下,不需要任何滑动效果;唯一所做的事便是将item从上往下依次罗列;
- 覆盖翻页
覆盖翻页模式下,在上面仿真翻页效果基础上,仅仅将滑动效果应用于当前最顶层的可见页;
- 滚动翻页
滚动翻页效果跟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的:
可以看到,其实paint方法中才是真正去计算 child 位置的地方,先看childMainAxisPosition方法:
在这里会去计算主轴的位置,依据便是之前在layout方法中,遍历child并给其parentData设置的layoutOffset参数,并减去当前已经滑动的距离;
交叉轴这块,则直接返回0
自此就算出了具体的相对位置,之后就传给paint方法进行绘制;
之后就是获取下一个child,再次循环上述流程;
而如果要实现上面提到的效果,要做的事也比较简单:
- 如果是效果1,那么一直将所有child的绘制位置改为0即可;
- 如果是效果2,那么仅仅在第一个child上加上scrollOffset的偏移量计算即可;
当然,由于绘制顺序的关系,获取child要先从lastChild获取,并不断取之前的child,直到第一个child;
如果再结合自定义路径,加入变化Item的能力,那就要引入设想的LayoutManager的能力;
在此先将这部分逻辑抽离,等LayoutManager调用使用;
结语:
这个滑动效果实现方式非常简单,麻烦的地方反而是如何将自定义SliverList的接进去~
下一步看下对Element层面的改造,暴露RenderObject 的layout、paint方法出去