【Flutter】小说阅读器改版记录 —— 踩了个Layer的坑

3,746 阅读2分钟

前言

时隔大半周后重回小说阅读器部分,这段时间除了摸鱼之外,最大的问题还是实现之前的这个设想:

按之前的设想,计划采用一个大ListView,里面放三个小ListView,分别代表上一章,当前章,下一章;通过支持嵌套滑动的方式,能无缝实现章节切换,也不用做什么上一章、下一章的切换管理,所做的事就一件,大ListView和小ListView分别构造对应Item,就这样就行了;想想都是一件美事,按这套方案实现出来的话,我倒很好奇谁还会说逻辑看不懂

于是呢,按这个思路给ListView加上了嵌套滑动功能;但是在仿真翻页这块却遇到了问题,由于仿真翻页会对canvas进行一个save和restore操作,来对canvas进行裁剪;如果在 save 和 restore 操作间通过 context.paintChild 绘制小ListView本身而非其Item(也就是大ListView接管手势时间,绘制其本身对应的ListView做个章节间的翻页动画的时候),会得到一个暖心的报错:

Object has been disposed.

结果嘛,经过几天的追踪分析与debug,终于明白出现这个问题的原因,以及做了临时性的解决方案;在此记录下还需要优化的部分;

其实原因很简单,就下面图中这块:

image.png

所以确定原因后,需要做的事就很明确了,处理一下ListView中RepaintBoundary的问题即可;

分析

再次细看一遍ListView的各个小部件后,确定下来有添加RepaintBondary的小部件为:GlowingOverscrollIndicatorViewPort,下面要做的事就是如何合理的将RepaintBoundary从其中剔除;

现在初步做法就是内部嵌套的ListView,如果检测到开启了嵌套模式,那么不添加OverScrollIndicator,ViewPort也使用一个自定义的,专门去掉了isRepaintBoundary的ViewPort;应该有更加合理的方式,比如说自定义一个RepaintBoundary,通过像之前自定义GestureRecognizer那样的方式给他搞个动态返回是否需要拦截Repaint;

结语

就这个问题卡了几天时间,最骚的是还发现 context.clipPathAndPaint 这个方法同样使用了canvas.restore ,但它就不报错呢……

回正题,最后效果:(webp yyds,再也不用gif了)

效果.webp

注意看第三页翻页的时候,左下角的章节index变化部分,确实为章节部分的切换;