RendererBinding · PipelineOwner · RenderObject · Layer
Flutter Framework · packages/flutter/lib/src/rendering
第一部分:概述与架构
第二部分:核心类
第三部分:Layer 系统
第四部分:流程与优化
Flutter 渲染管线是将 Widget 树转换为 像素的核心机制。
三棵树架构:
渲染管线阶段:
┌─────────────────────────────────────────────────┐
│ RendererBinding │
│ (渲染树与 Flutter Engine 之间的胶水层) │
├─────────────────────────────────────────────────┤
│ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ PipelineOwner │───▶│ RenderObject │ │
│ │ (管道所有者) │ │ (渲染对象树) │ │
│ └────────┬────────┘ └──────────┬──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ flushLayout() │ │ Layer Tree │ │
│ │ flushPaint() │ │ (合成层树) │ │
│ └─────────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────┘
渲染树与 Flutter Engine 之间的胶水层,管理多个独立的渲染树。
源码位置: packages/flutter/lib/src/rendering/binding.dart
mixin RendererBinding
on BindingBase, ServicesBinding, SchedulerBinding,
GestureBinding, SemanticsBinding, HitTestable {
// 根 PipelineOwner
late PipelineOwner _rootPipelineOwner;
PipelineOwner get rootPipelineOwner => _rootPipelineOwner;
// 管理的所有 RenderView
final Map<Object, RenderView> _viewIdToRenderView = {};
Iterable<RenderView> get renderViews => _viewIdToRenderView.values;
// 鼠标追踪器
MouseTracker? _mouseTracker;
}
@protected
void drawFrame() {
// 1. 布局阶段
rootPipelineOwner.flushLayout();
// 2. 更新合成位
rootPipelineOwner.flushCompositingBits();
// 3. 绘制阶段
rootPipelineOwner.flushPaint();
// 4. 合成阶段 - 发送到 GPU
if (sendFramesToEngine) {
for (final RenderView renderView in renderViews) {
renderView.compositeFrame();
}
// 5. 语义阶段
rootPipelineOwner.flushSemantics();
_firstFrameSent = true;
}
}
drawFrame() 是每帧渲染的核心入口,由 handleDrawFrame 调用。
管理渲染管线的所有者,驱动布局、绘制、合成、语义更新。
源码位置: packages/flutter/lib/src/rendering/object.dart
base class PipelineOwner with DiagnosticableTreeMixin {
PipelineOwner({
this.onNeedVisualUpdate,
this.onSemanticsOwnerCreated,
this.onSemanticsUpdate,
this.onSemanticsOwnerDisposed,
});
// 需要布局的节点
List<RenderObject> _nodesNeedingLayout = [];
// 需要绘制节点
List<RenderObject> _nodesNeedingPaint = [];
// 需要更新合成位的节点
final List<RenderObject> _nodesNeedingCompositingBitsUpdate = [];
// 根节点
RenderObject? _rootNode;
}
// 布局阶段
void flushLayout() {
while (_nodesNeedingLayout.isNotEmpty) {
final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
_nodesNeedingLayout = [];
// 按深度排序(从深到浅)
dirtyNodes.sort((a, b) => a.depth - b.depth);
for (var i = 0; i < dirtyNodes.length; i++) {
final RenderObject node = dirtyNodes[i];
if (node._needsLayout && node.owner == this) {
node._layoutWithoutResize();
}
}
}
// 递归处理子 PipelineOwner
for (final PipelineOwner child in _children) {
child.flushLayout();
}
}
┌────────────────────────────────────────────────┐
│ flushLayout() 入口 │
└───────────────────────┬────────────────────────┘
▼
┌────────────────────────────────────────────────┐
│ 获取 dirtyNodes 列表,按 depth 排序 │
│ (深度大的先处理,即子节点优先) │
└───────────────────────┬────────────────────────┘
▼
┌────────────────────────────────────────────────┐
│ 遍历 dirtyNodes: │
│ - 调用 node._layoutWithoutResize() │
│ - 内部调用 performLayout() │
│ - 子节点调用 child.layout(constraints) │
└───────────────────────┬────────────────────────┘
▼
┌────────────────────────────────────────────────┐
│ 递归调用子 PipelineOwner.flushLayout() │
└────────────────────────────────────────────────┘
渲染树中所有对象的基类,定义布局、绘制、命中测试协议。
源码位置: packages/flutter/lib/src/rendering/object.dart
abstract class RenderObject extends AbstractNode
with DiagnosticableTreeMixin {
// 所属 PipelineOwner
PipelineOwner? _owner;
// 父节点
RenderObject? _parent;
// 是否需要布局
bool _needsLayout = true;
// 是否需要绘制
bool _needsPaint = true;
// 是否是重绘边界
bool get isRepaintBoundary => false;
// 关联的 Layer
final LayerHandle<Layer> _layerHandle = LayerHandle<Layer>();
}
┌─────────────────────────────────────────────────┐
│ attach() │
│ (关联到 PipelineOwner) │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ markNeedsLayout() │
│ (标记需要布局,加入脏列表) │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ performLayout() │
│ (执行实际布局计算) │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ markNeedsPaint() │
│ (标记需要绘制) │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ paint() │
│ (执行绘制,生成 Layer 树) │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ detach() │
│ (从 PipelineOwner 分离) │
└─────────────────────────────────────────────────┘
2D 笛卡尔坐标系中的渲染对象,实现 Box 布局协议。
源码位置: packages/flutter/lib/src/rendering/box.dart
abstract class RenderBox extends RenderObject {
// 尺寸
Size get size => _size;
Size _size = Size.zero;
// 布局入口
void layout(Constraints constraints, { bool parentUsesSize = false }) {
// ...
}
// 子类实现具体布局逻辑
@protected
void performLayout();
// 干布局(不改变实际尺寸)
Size computeDryLayout(BoxConstraints constraints);
// 基线对齐
double? getDryBaseline(BoxConstraints constraints, TextBaseline baseline);
}
Box 布局的约束条件,描述宽高的最小/最大值。
class BoxConstraints extends Constraints {
const BoxConstraints({
this.minWidth = 0.0,
this.maxWidth = double.infinity,
this.minHeight = 0.0,
this.maxHeight = double.infinity,
});
final double minWidth;
final double maxWidth;
final double minHeight;
final double maxHeight;
// 紧约束(固定尺寸)
BoxConstraints.tight(Size size);
// 松约束(0 到最大值)
BoxConstraints.loose(Size size);
// 展开约束(填充父容器)
const BoxConstraints.expand({double? width, double? height});
}
| 类型 | 条件 | 说明 |
|---|---|---|
| Tight | min == max | 固定尺寸,无选择余地 |
| Loose | min == 0 | 可以从 0 到 max |
| Bounded | max < infinity | 有上界约束 |
| Unbounded | max == infinity | 无上界(如 ListView) |
| Expanding | min == max == infinity | 无限展开 |
验证方法:
bool get isTight => minWidth >= maxWidth && minHeight >= maxHeight;
bool get hasBoundedWidth => maxWidth < double.infinity;
bool get hasInfiniteWidth => minWidth >= double.infinity;
绘制上下文,管理 Canvas 和 Layer 树的构建。
源码位置: packages/flutter/lib/src/rendering/object.dart
class PaintingContext extends ClipContext {
PaintingContext(this._containerLayer, this.estimatedBounds);
final ContainerLayer _containerLayer;
final Rect estimatedBounds;
// 当前绘制的 Canvas
Canvas? _canvas;
Canvas get canvas {
if (_canvas == null) _startRecording();
return _canvas!;
}
// 绘制子节点
void paintChild(RenderObject child, Offset offset) {
if (child.isRepaintBoundary) {
_compositeChild(child, offset);
} else {
child._paintWithContext(this, offset);
}
}
}
// 重绘合成子节点
static void repaintCompositedChild(RenderObject child) {
var childLayer = child._layerHandle.layer as OffsetLayer?;
if (childLayer == null) {
// 创建新的 Layer
final OffsetLayer layer = child.updateCompositedLayer(oldLayer: null);
child._layerHandle.layer = childLayer = layer;
} else {
// 重用现有 Layer
childLayer.removeAllChildren();
child.updateCompositedLayer(oldLayer: childLayer);
}
// 创建绘制上下文并绘制
childContext = PaintingContext(childLayer, child.paintBounds);
child._paintWithContext(childContext, Offset.zero);
}
// 推送裁剪层
ClipRectLayer? pushClipRect(bool needsCompositing, Offset offset,
Rect clipRect, PaintingContextCallback painter);
// 推送变换层
TransformLayer? pushTransform(bool needsCompositing, Offset offset,
Matrix4 transform, PaintingContextCallback painter);
合成层树,由 Paint 阶段生成,最终发送到 GPU。
源码位置: packages/flutter/lib/src/rendering/layer.dart
abstract class Layer with DiagnosticableTreeMixin {
// 父节点
ContainerLayer? get parent => _parent;
ContainerLayer? _parent;
// 引擎层(用于 retained rendering)
ui.EngineLayer? _engineLayer;
// 是否需要添加到场景
bool _needsAddToScene = true;
// 添加到场景
@protected
void addToScene(ui.SceneBuilder builder);
// 标记需要更新
void markNeedsAddToScene() {
if (_needsAddToScene) return;
_needsAddToScene = true;
}
}
| Layer 类型 | 用途 |
|---|---|
| PictureLayer | 包含绘制指令的叶子层 |
| ContainerLayer | 包含子节点的容器层 |
| OffsetLayer | 带偏移的容器层 |
| ClipRectLayer | 矩形裁剪层 |
| ClipRRectLayer | 圆角矩形裁剪层 |
| ClipPathLayer | 路径裁剪层 |
| TransformLayer | 变换层 |
| OpacityLayer | 透明度层 |
| TextureLayer | 纹理层(视频/相机) |
包含子节点的容器层,管理子 Layer 的双向链表。
class ContainerLayer extends Layer {
// 第一个子节点
Layer? get firstChild => _firstChild;
Layer? _firstChild;
// 最后一个子节点
Layer? get lastChild => _lastChild;
Layer? _lastChild;
// 添加子节点
void append(Layer child) {
_adoptChild(child);
child._previousSibling = lastChild;
if (lastChild != null) lastChild!._nextSibling = child;
_lastChild = child;
_firstChild ??= child;
child._parentHandle.layer = child;
}
// 移除所有子节点
void removeAllChildren();
// 构建场景
ui.Scene buildScene(ui.SceneBuilder builder);
}
包含 ui.Picture 的叶子层,存储实际绘制指令。
class PictureLayer extends Layer {
PictureLayer(this.canvasBounds);
final Rect canvasBounds;
// 绘制内容
ui.Picture? get picture => _picture;
ui.Picture? _picture;
set picture(ui.Picture? picture) {
markNeedsAddToScene();
_picture?.dispose();
_picture = picture;
}
// 光栅化缓存提示
bool get isComplexHint => _isComplexHint;
bool get willChangeHint => _willChangeHint;
@override
void addToScene(ui.SceneBuilder builder) {
builder.addPicture(Offset.zero, picture!,
isComplexHint: isComplexHint, willChangeHint: willChangeHint);
}
}
带偏移的容器层,子节点相对于此层有偏移。
class OffsetLayer extends ContainerLayer {
OffsetLayer({ Offset offset = Offset.zero }) : _offset = offset;
// 偏移量
Offset get offset => _offset;
Offset _offset;
set offset(Offset value) {
if (value != _offset) {
_offset = value;
markNeedsAddToScene();
}
}
@override
void addToScene(ui.SceneBuilder builder) {
engineLayer = builder.pushOffset(
offset.dx,
offset.dy,
oldLayer: _engineLayer as ui.OffsetEngineLayer?,
);
addChildrenToScene(builder);
builder.pop();
}
// 转换为图片
Future<ui.Image> toImage(Offset offset, int width, int height);
}
矩形裁剪层,限制子节点的可见区域。
class ClipRectLayer extends ContainerLayer {
ClipRectLayer({ Rect? clipRect, Clip clipBehavior = Clip.hardEdge })
: _clipRect = clipRect, _clipBehavior = clipBehavior;
Rect? get clipRect => _clipRect;
Rect? _clipRect;
set clipRect(Rect? value) {
if (value != _clipRect) {
_clipRect = value;
markNeedsAddToScene();
}
}
Clip get clipBehavior => _clipBehavior;
Clip _clipBehavior;
set clipBehavior(Clip value) {
if (value != _clipBehavior) {
_clipBehavior = value;
markNeedsAddToScene();
}
}
@override
void addToScene(ui.SceneBuilder builder) {
engineLayer = builder.pushClipRect(
clipRect!,
clipBehavior: clipBehavior,
oldLayer: _engineLayer as ui.ClipRectEngineLayer?,
);
addChildrenToScene(builder);
builder.pop();
}
}
变换层,对子节点应用矩阵变换。
class TransformLayer extends ContainerLayer {
TransformLayer({ Matrix4? transform }) : _transform = transform;
Matrix4? get transform => _transform;
Matrix4? _transform;
set transform(Matrix4? value) {
if (value != _transform) {
_transform = value;
markNeedsAddToScene();
}
}
@override
void addToScene(ui.SceneBuilder builder) {
engineLayer = builder.pushTransform(
transform!.storage,
oldLayer: _engineLayer as ui.TransformEngineLayer?,
);
addChildrenToScene(builder);
builder.pop();
}
// 应用变换到子节点
@override
void applyTransform(Layer child, Matrix4 transform) {
transform.multiply(this.transform!);
}
}
透明度层,对子节点应用透明度混合。
class OpacityLayer extends ContainerLayer {
OpacityLayer({ int alpha = 255, Offset offset = Offset.zero })
: _alpha = alpha, _offset = offset;
// 透明度 (0-255)
int get alpha => _alpha;
int _alpha;
set alpha(int value) {
if (value != _alpha) {
_alpha = value;
markNeedsAddToScene();
}
}
Offset get offset => _offset;
Offset _offset;
@override
void addToScene(ui.SceneBuilder builder) {
engineLayer = builder.pushOpacity(
alpha,
offset: offset,
oldLayer: _engineLayer as ui.OpacityEngineLayer?,
);
addChildrenToScene(builder);
builder.pop();
}
}
Layer 资源管理句柄,防止 Layer 被过早释放。
class LayerHandle<T extends Layer> {
LayerHandle([this._layer]) {
if (_layer != null) {
_layer!._refCount += 1; // 增加引用计数
}
}
T? _layer;
T? get layer => _layer;
set layer(T? layer) {
if (identical(layer, _layer)) return;
_layer?._unref(); // 减少旧 Layer 引用计数
_layer = layer;
if (_layer != null) {
_layer!._refCount += 1; // 增加新 Layer 引用计数
}
}
}
// RenderObject 中使用
class MyRenderObject extends RenderBox {
final LayerHandle<ClipRectLayer> _clipLayer = LayerHandle();
@override
void dispose() {
_clipLayer.layer = null; // 释放句柄
super.dispose();
}
}
渲染树的根节点,连接 PipelineOwner 和 FlutterView。
class RenderView extends RenderObject {
RenderView({ required FlutterView view }) : _flutterView = view;
final FlutterView _flutterView;
FlutterView get flutterView => _flutterView;
// 视图配置
ViewConfiguration get configuration => _configuration;
ViewConfiguration _configuration;
set configuration(ViewConfiguration value) {
if (_configuration != value) {
_configuration = value;
markNeedsLayout();
}
}
// 唯一子节点
RenderObject? get child => _child;
RenderObject? _child;
set child(RenderObject? value) {
_child = value;
markNeedsLayout();
}
// 合成帧 - 发送到 GPU
void compositeFrame() {
final ui.SceneBuilder builder = RendererBinding.instance.createSceneBuilder();
final ui.Scene scene = layer!.buildScene(builder);
_flutterView.render(scene);
scene.dispose();
}
}
┌─────────────────────────────────────────────────┐
│ handleBeginFrame() │
│ (处理动画、Transient 回调) │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ handleDrawFrame() │
│ (调用 drawFrame()) │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ 1. flushLayout() - 布局所有 dirty 节点 │
│ 2. flushCompositingBits() - 更新合成位 │
│ 3. flushPaint() - 绘制所有 dirty 节点 │
│ 4. compositeFrame() - 发送 Scene 到 GPU │
│ 5. flushSemantics() - 更新语义树 │
└───────────────────────┬─────────────────────────┘
▼
┌─────────────────────────────────────────────────┐
│ postFrameCallbacks() │
│ (帧后回调) │
└─────────────────────────────────────────────────┘
VSync Signal
│
▼
┌────────────────────────────────────────────────┐
│ BEGIN FRAME │
│ ┌────────────────────────────────────────────┐ │
│ │ Transient Frame Callbacks (动画更新) │ │
│ └────────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ DRAW FRAME │
│ ┌────────────────────────────────────────────┐ │
│ │ Persistent Frame Callback (drawFrame) │ │
│ │ ├─ flushLayout() ~2-5ms │ │
│ │ ├─ flushCompositingBits() ~0.1ms │ │
│ │ ├─ flushPaint() ~2-5ms │ │
│ │ ├─ compositeFrame() ~0.5ms │ │
│ │ └─ flushSemantics() ~1-3ms │ │
│ └────────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ GPU RASTERIZATION │
│ (Layer Tree → Textures → Screen) │
└────────────────────────────────────────────────┘
布局是单向数据流:约束向下传递,尺寸向上返回。
布局协议:
// 典型布局实现
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
// 布局子节点
final RenderBox child = this.child!;
child.layout(constraints, parentUsesSize: true);
// 使用子节点尺寸
size = child.size;
// 定位子节点
final BoxParentData childParentData = child.parentData as BoxParentData;
childParentData.offset = Offset.zero;
}
绘制生成 Layer 树,记录所有绘制指令。
绘制协议:
// 典型绘制实现
@override
void paint(PaintingContext context, Offset offset) {
// 绘制背景
context.canvas.drawRect(offset & size, Paint()..color = Colors.blue);
// 绘制子节点
if (child != null) {
final BoxParentData childParentData = child!.parentData as BoxParentData;
context.paintChild(child!, offset + childParentData.offset);
}
// 绘制前景
context.canvas.drawRect(offset & size, Paint()
..color = Colors.red
..style = PaintingStyle.stroke);
}
将 Layer 树转换为 Scene,发送到 GPU 光栅化。
// RenderView.compositeFrame()
void compositeFrame() {
// 1. 创建 SceneBuilder
final ui.SceneBuilder builder = RendererBinding.instance.createSceneBuilder();
// 2. Layer 树构建 Scene
final ui.Scene scene = layer!.buildScene(builder);
// 3. 发送到 FlutterView 渲染
_flutterView.render(scene);
// 4. 释放 Scene
scene.dispose();
}
// ContainerLayer.buildScene()
ui.Scene buildScene(ui.SceneBuilder builder) {
updateSubtreeNeedsAddToScene();
addToScene(builder);
if (subtreeHasCompositionCallbacks) {
_fireCompositionCallbacks(includeChildren: true);
}
_needsAddToScene = false;
return builder.build();
}
重绘边界,创建独立的 Layer,隔离子树的重绘。
作用:
// RenderObject 中的判断
bool get isRepaintBoundary => false; // 默认不是
// PaintingContext.paintChild()
void paintChild(RenderObject child, Offset offset) {
if (child.isRepaintBoundary) {
// 子节点是重绘边界,创建独立 Layer
stopRecordingIfNeeded();
_compositeChild(child, offset);
} else {
// 直接绘制到当前 Canvas
child._paintWithContext(this, offset);
}
}
┌────────────────────────────────────────────────┐
│ Parent Layer │
│ ┌──────────────────────────────────────────┐ │
│ │ PictureLayer (Parent) │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ OffsetLayer (RepaintBoundary) │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ PictureLayer (Child subtree) │ │ │
│ │ └────────────────────────────────────┘ │ │
│ │ [子树重绘只更新这个 Layer] │ │ │
│ └──────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
子树 markNeedsPaint() 时:
1. 只标记 RepaintBoundary 节点为 dirty
2. flushPaint() 只重绘该 Layer
3. 父 Layer 不受影响
父节点存储在子节点上的数据,如位置、布局参数。
// 基类
class ParentData {
@protected
@mustCallSuper
void detach() {}
}
// Box 布局使用
class BoxParentData extends ParentData {
// 子节点相对于父节点的偏移
Offset offset = Offset.zero;
}
// 容器使用
abstract class ContainerBoxParentData<ChildType extends RenderObject>
extends BoxParentData
with ContainerParentDataMixin<ChildType> {
// ContainerParentDataMixin 提供:
// - previousSibling
// - nextSibling
}
// 使用示例
final BoxParentData childParentData = child.parentData as BoxParentData;
childParentData.offset = Offset(10, 20);
命中测试,确定触摸事件应该由哪个 RenderObject 处理。
测试顺序:
// RenderBox.hitTest()
bool hitTest(BoxHitTestResult result, { required Offset position }) {
// 1. 检查是否在边界内
if (_size!.contains(position)) {
// 2. 检查子节点
if (hitTestChildren(result, position: position) || hitTestSelf(position)) {
// 3. 添加到结果
result.add(BoxHitTestEntry(this, position));
return true;
}
}
return false;
}
触摸点 (100, 200)
│
▼
┌──────────────────────────────────────────────┐
│ RenderView.hitTest() │
│ 检查 (100, 200) 是否在视图内 │
└─────────────────────┬────────────────────────┘
▼
┌──────────────────────────────────────────────┐
│ hitTestChildren() - 从后往前遍历 │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Child 3 │ │ Child 2 │ ... │
│ │ (最上层) │ │ │ │
│ └──────┬──────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ 命中? ──Yes──▶ 添加到 HitTestResult │
│ │ │
│ No │
│ ▼ │
│ 测试下一个子节点 │
└──────────────────────────────────────────────┘
用于辅助功能(屏幕阅读器)的语义信息树。
生成时机:
// RenderObject 中的语义相关方法
void describeSemanticsConfiguration(SemanticsConfiguration config) {
// 描述语义配置
config.isSemanticBoundary = true;
}
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config,
Iterable<SemanticsNode> children) {
// 组装语义节点
}
// PipelineOwner.flushSemantics()
void flushSemantics() {
for (final RenderObject node in _nodesNeedingSemantics) {
if (node._needsSemanticsUpdate && node.owner == this) {
node._updateSemantics();
}
}
}
Flutter 渲染管线使用了多种经典设计模式。
结构型模式:
行为型模式:
RenderObject 树是典型的组合模式实现。
// 抽象组件
abstract class RenderObject {
RenderObject? _parent;
void visitChildren(RenderObjectVisitor visitor) { }
void visitChildrenForSemantics(RenderObjectVisitor visitor) {
visitChildren(visitor);
}
}
// 叶子节点
class RenderImage extends RenderBox {
@override
void visitChildren(RenderObjectVisitor visitor) {
// 无子节点,什么都不做
}
}
// 组合节点
class RenderStack extends RenderBox {
@override
void visitChildren(RenderObjectVisitor visitor) {
for (final RenderBox child in _children) {
visitor(child);
}
}
}
遍历渲染树的标准方式。
// 访问者函数签名
typedef RenderObjectVisitor = void Function(RenderObject child);
// 遍历子节点
void visitChildren(RenderObjectVisitor visitor) {
// 子类实现具体遍历逻辑
}
// 使用示例
void _paintWithContext(PaintingContext context, Offset offset) {
// ...
}
// 遍历所有后代
void visitAllDescendants(RenderObjectVisitor visitor) {
void recursiveVisitor(RenderObject child) {
visitor(child);
child.visitChildren(recursiveVisitor);
}
visitChildren(recursiveVisitor);
}
通过 markNeeds* 方法通知系统状态变化。
// 标记需要布局
void markNeedsLayout() {
if (_needsLayout) return;
_needsLayout = true;
if (_relayoutBoundary == this) {
// 自己是布局边界,直接加入脏列表
owner!._nodesNeedingLayout.add(this);
owner!.requestVisualUpdate();
} else {
// 否则向上传播到布局边界
_parent!.markNeedsLayout();
}
}
// 标记需要绘制
void markNeedsPaint() {
if (_needsPaint) return;
_needsPaint = true;
if (isRepaintBoundary) {
// 自己是重绘边界
owner!._nodesNeedingPaint.add(this);
owner!.requestVisualUpdate();
} else if (_parent != null) {
// 向上传播
_parent!.markNeedsPaint();
}
}
Flutter 渲染管线内置多种优化机制。
核心优化:
// Retained Rendering 示例
void _addToSceneWithRetainedRendering(ui.SceneBuilder builder) {
if (!_needsAddToScene && _engineLayer != null) {
// 重用上一帧的引擎层
builder.addRetained(_engineLayer!);
return;
}
// 需要重新构建
addToScene(builder);
_needsAddToScene = false;
}
| 策略 | 场景 | 效果 |
|---|---|---|
| RepaintBoundary | 频繁更新的子树 | 隔离重绘 |
| isComplexHint | 复杂绘制内容 | 启用光栅缓存 |
| willChangeHint | 频繁变化的内容 | 禁用光栅缓存 |
| const Widget | 静态内容 | 跳过重建 |
| ListView.builder | 长列表 | 懒加载 |
光栅缓存,将 Layer 光栅化结果缓存为纹理。
工作原理:
// 设置缓存提示
@override
void paint(PaintingContext context, Offset offset) {
// 复杂绘制
_drawComplexContent(context.canvas, offset);
// 提示这是一个复杂层,应该缓存
context.setIsComplexHint();
// 或者提示这个层会频繁变化,不应该缓存
// context.setWillChangeHint();
}
DevTools:
命令行工具:
flutter run --profileflutter screenshotflutter drive// 启用性能覆盖层
MaterialApp(
showPerformanceOverlay: true,
home: MyHomePage(),
);
// 调试标志
debugProfilePaintsEnabled = true;
debugRepaintRainbowEnabled = true;
debugPrintMarkNeedsLayoutStacks = true;
布局优化:
绘制优化:
布局反模式:
// ❌ 错误:在布局中创建对象
@override
void performLayout() {
final List<RenderBox> children = []; // 每帧创建!
visitChildren((child) => children.add(child));
}
// ✅ 正确:复用成员变量
final List<RenderBox> _cachedChildren = [];
@override
void performLayout() {
_cachedChildren.clear();
visitChildren((child) => _cachedChildren.add(child));
}
绘制反模式:
// ❌ 错误:每次绘制创建 Paint
@override
void paint(context, offset) {
final paint = Paint()..color = Colors.blue; // 每帧创建!
}
// ✅ 正确:复用 Paint
final _paint = Paint()..color = Colors.blue;
@override
void paint(context, offset) {
context.canvas.drawRect(rect, _paint);
}
// 打印渲染树
debugDumpRenderTree();
// 打印 Layer 树
debugDumpLayerTree();
// 打印语义树
debugDumpSemanticsTree();
// 可视化重绘边界
debugRepaintRainbowEnabled = true;
// 可视化布局边界
debugPaintSizeEnabled = true;
debugPaintBaselinesEnabled = true;
// 打印布局调用栈
debugPrintMarkNeedsLayoutStacks = true;
// 打印绘制调用栈
debugPrintMarkNeedsPaintStacks = true;
// 检测不必要的重绘
debugProfilePaintsEnabled = true;
源码文件:
rendering/binding.dartrendering/object.dartrendering/box.dartrendering/layer.dartrendering/proxy_box.dart核心概念:
渲染流程:
Widget → Element → RenderObject → Layout → Paint → Layer → Scene → GPU
优化要点:
GitHub 源码:
🦋 Flutter 渲染管线深度解析
51 页 · 深入源码分析
Generated by OpenClaw · ATCFU