最近在做一个长列表的功能时, 发现即使使用了SliverList , 但在老机型也还是很卡,
并且竞品不存在这样的问题, 而且列表会随着 item 数量增加越来越卡,
似乎重用根本没有生效 😭
这种问题很显然在高性能的机器或者模拟器时难以明显的发现或者调试
最终知道是什么原因导致的解决起来就很简单了,
也就是 CustomScrollView 下的列表要直接作为它的 slivers ,
而不是再包到其他组件下在放在它的里面
但在结构比较复杂的多人参与的项目, 和 flutter 组件一层一层包子组件的想法下,
寻找原因时却容易忽略或难以发现这个问题,
这就需要有一个确定元素有没有成功重用的方法
那么除了找性能弱的老机型和竞品来测试, 在组件树中上下翻滚查看和用性能分析工具对比修改前后的变化外,
有没有简单直观的工具, 能帮助我们方便的确定是否重用成功呢 (好吧,标题已经剧透了)
Flutter DevTools 的 **Highlight Repaints **工具就能帮助我们做到这一点
打开它后会在我们的 UI 上给各种元素添加带有颜色的框,
当元素重绘时, 框的颜色就会按照时间进行彩虹色的变化
虽然它主要用于检查有没有元素被多次重绘, 不过在检测列表重用是否成功时也非常有用
接下来我们用一个展示 Material Icons 的列表来作为演示
在我们的列表没有成功重用,时由于整个列表的元素一开始都渲染好了,每个 item 都在 Widget Tree 上,
在我们滑动列表时,元素的方框颜色不会有变化,只有整个列表的外层在变换颜色, 很显然重用没有成功

在列表成功重用的情况下, 由于前后的 item 在滚动到它的时候才被重用也就是视图进行了更新, 那么我们滑动时就能看到方框颜色不一样的 item, 在快速滑动时还会呈现出彩虹的效果

这样直观的反馈很适合我们在模拟器,
或性能较高导致重用带来的性能提升效果不明显的真机上调试时, 来发现和确认是否有问题
当然,有时候可能 DevTools 自动框选的范围并不是我们想要的,希望更进一步细化到指定的元素
比如假设我们需要让列表里的部分图标旋转并查看它们的更新情况
(这个例子有点怪,不过大概就是更精细的看视图更新的方式演示吧)
这个时候我们可以直接在图标代码外加入 RepaintBoundary 来做到对元素添加这样的方框进行调试
在没有添加前我们发现图标旋转时,
整个列表的方框颜色都在变化,不方便我们对图标变化和更新的确认

所以接下来让我们对代码进行修改
在导入相关的包并启用
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; // 导入包
void main() {
debugRepaintRainbowEnabled = true; // 启用重绘高亮
runApp(MyApp());
}
然后在需要的元素上添加RepaintBoundary后
@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: RotationTransition(
turns: Tween(begin: 0.0, end: 1.0).animate(_controller),
child: Icon(widget.iconData,
color: Theme.of(context).colorScheme.primary, size: 24),
),
);
}
只有旋转的图标本身的框会变换颜色
这样细化的更方便我们进行调试
------------------------------ 结尾 ------------------------
Flutter DevTools 里还有很多类似这样的工具也许能有时候帮助我们快速调试:
Select Widget Mode: 在点击组件后直接跳转到对应 Widget Tree 位置和代码
Slow Animations: 以五分之一的速度运行动画, 以便对它们进行优化
Show Guidelines: 覆盖一层引导线以帮助调整布局问题
Show Baselines: 针对文字对齐展示文字的基线, 对检查文字是否对齐有帮助
Highlight Oversized Images: 该选项通过反转颜色和垂直翻转来突出显示过大的图像, 高亮显示的图像使用的内存超过了所需内存,例如,以 100 x 100 像素显示的 5MB 大图像
参考: