IT之家Flutter知识

Keframe 分帧入屏: 处理flutter卡顿,优化流畅度

2021-09-23  本文已影响0人  李小轰

引言

在掘金上浏览到Nayuta开源的贝壳flutter流畅优化组件 Keframe。在Demo上试用了一番,确有奇效,下面记录一下笔记心得。

Keframe 处理思路

Keframe 方案:分帧入屏 ,既然单帧的绘制时间太长,那我们就将一帧分成多帧。
将屏幕上的 widget 扔进一个执行队列,将模块内的时间做拆分,多个 widget 不同时进行绘制,一个绘制完成后再进行下一个 widget 的绘制。

Keframe 使用方法
dependencies:
  keframe: version
// CellWidget 是一个复杂的Item widget
ListView.builder(
      itemCount: 100t,
      itemBuilder: (c, i) => CellWidget(),
    )
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 将不会出现跳动情况。


原理分析

  • initState 初始化时 resultWidget 赋值为占位Widget
  • transformWidget initState和didUpdate都会触发,监听占位绘制完成,并将替换任务扔进分帧队列中
FrameSeparateTaskQueue
  • await SchedulerBinding.instance!.endOfFrame : 如果当前正在绘制,等待当前帧结束。如果当前空闲,强制进行一帧的绘制,并等待结束。
  • await taskItemQueue.first.run() : 该方法为callback回调,真实内容就是替换占位widget
//自定义冒泡通知
class LayoutInfoNotification extends Notification {
  final Size size;
  final int? index;
  LayoutInfoNotification(this.index, this.size);
}
子组件
父组件

子组件重写performLayout方法,将尺寸大小通过冒泡通知给父组件,父组件根据id进行存储。

上一篇 下一篇

猜你喜欢

热点阅读