引言
在掘金上浏览到Nayuta
开源的贝壳flutter流畅优化组件 Keframe。在Demo上试用了一番,确有奇效,下面记录一下笔记心得。
Keframe 处理思路
- 卡顿的本质
在一帧内,模块运行的时间太长,计算量太大
Keframe 方案:分帧入屏 ,既然单帧的绘制时间太长,那我们就将一帧分成多帧。
将屏幕上的 widget 扔进一个执行队列,将模块内的时间做拆分,多个 widget 不同时进行绘制,一个绘制完成后再进行下一个 widget 的绘制。
Keframe 使用方法
- 添加依赖(非空安全使用: 1.0.2; 空安全版本使用: 2.0.2)
dependencies:
keframe: version
- 优化前的代码
// CellWidget 是一个复杂的Item widget
ListView.builder(
itemCount: 100t,
itemBuilder: (c, i) => CellWidget(),
)
- 使用
Keframe
优化
ListView.builder(
itemCount: 100t,
itemBuilder: (c, i) => FrameSeparateWidget(
index: i,
placeHolder: placeHolderWidget(),
widget: CellWidget(),
),
)
FrameSeparateWidget
: 分屏组件
index
: id标识,非必传,使用SizeCacheWidget
的场景必传
placeHolder
: 占位widget
widget
: 真实需要渲染的widget
借用一下作者的图解:
假如现在页面由 A、B、C、D 四部分组成,每部分耗时 10ms,在页面时构建为 40ms。使用分帧组件 FrameSeparateWidget 嵌套每一个部分。页面构建时会在第一帧渲染简单的占位,在后续四帧内分别渲染 A、B、C、D。
另外 Keframe
还提供了一个工具类SizeCacheWidget
用于缓存子节点中,分帧组件嵌套的实际 widget 的尺寸信息。对于列表,在每一个 item 中嵌套 FrameSeparateWidget,并将 ListView 嵌套在 SizeCacheWidget 内即可。
SizeCacheWidget(
child: ListView.builder(
...省略
itemBuilder: (c, i) => FrameSeparateWidget(
...省略
),
),
)
SizeCacheWidget 的作用:
当不确定实际 item 高度的时候,给 placeholder 设置一个近似的高度。并且在将 ListView 嵌套在 SizeCacheWidget 中。记录已渲染 widget 的大小尺寸,对于已渲染过的 widget 设置占位的尺寸。在滚动过程中,已经渲染过的 item 将不会出现跳动情况。
原理分析
-
分帧入屏
FrameSeparateWidget
FrameSeparateTaskQueue
initState
初始化时 resultWidget 赋值为占位WidgettransformWidget
initState和didUpdate都会触发,监听占位绘制完成,并将替换任务扔进分帧队列中
await SchedulerBinding.instance!.endOfFrame
: 如果当前正在绘制,等待当前帧结束。如果当前空闲,强制进行一帧的绘制,并等待结束。await taskItemQueue.first.run()
: 该方法为callback回调,真实内容就是替换占位widget
- SizeCacheWidget
//自定义冒泡通知
class LayoutInfoNotification extends Notification {
final Size size;
final int? index;
LayoutInfoNotification(this.index, this.size);
}
子组件
父组件
子组件重写
performLayout
方法,将尺寸大小通过冒泡通知
给父组件,父组件根据id进行存储。
网友评论