Flutter drawFrame()
RendererBinding.drawFrame() 负责生成帧。这个方法对于理解 Flutter 渲染过程非常重要。简单了解下。
RendererBinding.drawFrame() 由 SchedulerBinding.handleDrawFrame() 方法调用,而后者又自动被引擎调用(如果引擎需要布局和绘制一帧的话)。
RendererBinding.drawFrame() 的源码如下:
1 | void drawFrame() { |
flushPaint() 调用 PaintingContext.repaintCompositedChild(node) 方法,后者是真正的绘制逻辑。
每帧由以下几个阶段组成:
- 动画阶段 -
SchedulerBinding.handleBeginFrame(由Window.onBeginFrame注册),按注册顺序调用所有的临时帧回调 (由scheduleFrameCallback注册)。这些回调包括所有用于驱动AnimationController对象的Ticker实例,即该时间点的所有活跃Animation对象。 - Microtasks -
handleBeginFrame返回后,由临时帧回调注册的方法调度的 microtasks 开始运行。之后,由Window.onDrawFrame注册的handleDrawFrame回调开始执行,它调用所有的持久帧回调。其中最重要的是drawFrame方法,它的处理过程如下 - 布局阶段 - 对系统中的所有标记为脏的
RenderObject(如何将对象标脏以便布局,可参考RenderObject.markNeedsLayout) 进行布局 - compositing bits 阶段 - 更新所有标脏
RenderObject中的 compositing bits。具体参考RenderObject.markNeedsCompositingBitsUpdate - 绘制阶段 - 系统中的所有标脏
RenderObject被重绘。这个过程生成Layer树。如何将对象标脏以便绘制,可参考RenderObject.markNeedsPaint - 合成阶段 - 将 layer tree 转换成
Scene并发送到 GPU - semantics 阶段 - 系统中的所有标脏
RenderObject的 semantics 被更新。具体见RenderObject.semanticsAnnotator。这个过程生成SemanticsNode树。如何将对象标脏以用于 semantics,可参考RenderObject.markNeedsSemanticsUpdate - 步骤 3-7 的细节请参考
PipelineOwner - 结束阶段 -
drawFrame返回后,handleDrawFrame调用 post-frame 回调。(由addPostFrameCallback注册)
注意:某些绑定会向上述过程添加额外步骤,比如,WidgetsBinding 会添加 WidgetsBinding.drawFrame。