【Flutter】小说阅读器改版 (二)—— 改进一下仿真翻页的效果

3,066 阅读4分钟

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

前言

现在所需的ListView改造好了,可以去将ListView应用到小说阅读器上;但是按照之前的实现,现在还需要实现一些准备部分;

要实现的效果:

首先,在之前的文中,仅仅实现了覆盖翻页的LayoutManager,仿真翻页也需要一个,不过这次挑战一下更仿真的仿真翻页(参考小米阅读App的仿真翻页效果)

在之前项目中,前一页的翻页效果跟后一页是一样的,除了方向并无区别;

而在小米阅读上,效果是从前往后翻到指定位置:

小米阅读.gif

分析

要实现这种效果,我想有两种思路:

  • 第一种:固定加载两页,当触发手势操作的时候,第一页固定展示最顶层的效果;而不是固定展示最顶层的那页(举个例子,如果有1,2,3三页,当前处于第二页,往前翻的时候,第一页展示的是第一页,第二页处于底部,展示第二页的部分;但往后翻的时候,第一页展示的是当前所看的第二页的效果,第二页展示第三页的部分)

  • 第二种:固定内容跟Item绑定,结合ScrollController和其所持有的position,计算各种操作应该变化多少offset,再通过之前提供出来的手势信息,让各个Item自己判断是否要展示翻页效果;(这种情况下举例的话,应该是动态加载的两页,这两页绑定所展示的内容,还是之前的那个例子,往前翻,ListView先改变offset到特定位置,然后第一页展示翻页效果,第二页展示第二页;往后翻,第二页展示第二页的翻页效果,第三页就展示第三页;)

第一种思路,就是之前通过canvas来实现的效果;优点就是省事,缺点嘛,也很明显,各种页面切换,不好上手理解;

第二种思路,就是我现在想实现的方式,优点就是让Item只通过数据驱动,没有什么状态切换之类的东西;缺点就是会复杂不少,毕竟要通过数据来驱动;而非直接修改;

实现:

以手势操作开始分析:

  • 因为仅仅是移动的时候生效,所以很明显是move事件触发的,那么如果我 move 事件触发的时候,将Item移动到指针所在的位置,然后Item绘制翻页效果的时候,指针的横向坐标使用offset偏移量,纵向还是用指针的纵坐标,这种方式是否可以呢?

将Item移动到指定位置,可以通过ScrollController的 animateTo 方式来实现;

之前的分析中也说明了,可以通过 Controller 来获取 position ,里面保存了包括偏移量,Item宽度等信息,这样也可以计算出要移动到的位置;

看上去好像没什么问题?

做个小型demo实验一下,为了方便看出效果,以覆盖翻页的layoutManager为例,并仅仅计算处理一次move事件简单验证下:

QQ20211122-202229-HD.gif

确实是可以在move事件中调用animateTo方法改变offset;但是也发现一个问题,后续的拖动事件全部失效~

原因嘛,是因为animateTo方法会调用beginActivity,这个新的activity是 DrivenScrollActivity ,因为调用了新的activity,drag的activity会被中断销毁:

image.png

但是drag仅仅在dragStart的时候创建,所以后续的move事件调用不到drag来处理,自然没有效果~~~

image.png

image.png

结尾

看来要想以第二种方式来实现小米阅读的效果;也没那么轻松,接下来的想法是对 ScrollActivity 进行处理;如果在现在的效果上,能不中断drag,自然所有问题就能解决,接下来我会先尝试以下两个方法:

  • 自定义ScrollActivity,接管drag和那个负责animatedTo的DrivenScrollActivity?这样他俩都是一个东西,自然不会冲突销毁;
  • 对beginActivity进行修改,让其在特定条件下不去销毁drag;通过优先级来对任务调度;
  • 自己看看能否实现一个新的animatedTo方法,通过不断模拟drag事件的方式来触发;