Flutter框架源码深度分析
引擎架构与渲染管线核心对象模型与树结构布局系统深度剖析渲染系统实现细节状态管理与更新机制事件处理与手势识别动画系统实现应用启动与渲染流程性能优化原理生成HTML文档指南Flutter引擎架构采用分层设计,从底层到顶层包括:Flutter引擎的C++代码主要位于目录下,核心组件包括:Shell是Flutter引擎的主要入口点,在Android平台上通过和启动,在iOS平台上通过启动。关键代码: Sh
Flutter框架源码深度分析
1. 引擎架构与渲染管线
1.1 Flutter引擎架构
Flutter引擎架构采用分层设计,从底层到顶层包括:
+-------------------------+
| Dart Framework | <- 用户使用的Flutter框架(Material, Cupertino等)
+-------------------------+
| Flutter Engine | <- 渲染引擎(Skia)、平台通道、Dart VM
+-------------------------+
| Embedder (Platform) | <- 平台特定嵌入层(Android/iOS/Web等)
+-------------------------+
Flutter引擎的C++代码主要位于engine/src
目录下,核心组件包括:
- Shell: 引擎的外壳,负责协调各个子系统
- Dart VM: 执行Dart代码的虚拟机
- Skia: 跨平台2D渲染引擎
- Text: 文本渲染引擎
- Platform Channels: 平台通道,用于Flutter与原生平台通信
Shell是Flutter引擎的主要入口点,在Android平台上通过FlutterActivity
和FlutterView
启动,在iOS平台上通过FlutterViewController
启动。
关键代码: Shell初始化
// engine/src/flutter/shell/common/shell.cc
Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
: task_runners_(std::move(task_runners)),
settings_(std::move(settings)),
vm_(std::move(vm)),
weak_factory_(this) {
FML_DCHECK(task_runners_.IsValid());
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
// Initialize the engine components.
service_protocol_handler_ = std::make_unique<ServiceProtocolHandler>(
task_runners_.GetUITaskRunner(),
task_runners_.GetIOTaskRunner(),
task_runners_.GetPlatformTaskRunner(),
this);
// 创建引擎实例
engine_ = std::make_unique<Engine>(
*this,
/*delegate=*/nullptr,
/*snapshot_delegate=*/nullptr,
/*io_manager=*/nullptr,
/*unref_queue=*/nullptr,
task_runners_,
settings_,
std::move(vm_));
display_manager_ = std::make_unique<DisplayManager>();
}
Flutter引擎的生命周期主要由以下几个阶段组成:
- 初始化: 创建Shell和Engine实例
- 运行: 执行Dart代码,处理渲染和事件
- 销毁: 清理资源
1.2 Skia渲染引擎
Flutter使用Google的Skia引擎作为其2D渲染引擎,Skia是一个开源的跨平台2D图形库,提供了统一的API来绘制文本、几何图形和图像。
Skia渲染过程主要包含以下核心对象:
- SkCanvas: 提供绘制操作的接口
- SkPaint: 定义如何绘制(颜色、样式、字体等)
- SkPath: 定义要绘制的形状
- SkPicture: 记录绘制命令的序列,可回放
Flutter通过ui.Canvas
类封装了Skia的SkCanvas接口,提供给Dart层使用:
// 在Flutter的Dart代码中,Canvas类是对Skia的SkCanvas的封装
// flutter/lib/ui/painting.dart
class Canvas extends NativeFieldWrapperClass2 {
// Native方法,调用Skia的drawRect方法
void drawRect(Rect rect, Paint paint) {
_drawRect(rect.left, rect.top, rect.right, rect.bottom, paint);
}
// 底层Native实现
<Void Function(Pointer<Void>, Double, Double, Double, Double, Pointer<Void>)>(symbol: 'Canvas_drawRect')
external void _drawRect(double left, double top, double right, double bottom, Paint paint);
}
底层C++实现在engine/src/flutter/lib/ui/painting/canvas.cc
:
void Canvas::drawRect(double left, double top, double right, double bottom,
const Paint& paint) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkiaObjectStore::DartWrappable::AssertDartObjectNotCollected(paint);
canvas_->drawRect(rect, *paint.paint());
}
1.3 渲染管线完整流程
Flutter的渲染管线是一个复杂的流程,从Dart层到GPU渲染,完整的渲染管线如下图所示:
+------------------+ +------------------+ +------------------+
| Dart UI代码 |---->| Widget树构建 |---->| Element树更新 |
+------------------+ +------------------+ +------------------+
| |
v v
+------------------+ +------------------+ +------------------+
| RenderObject树 |<----| 布局与绘制阶段 |---->| 图层树构建 |
+------------------+ +------------------+ +------------------+
| |
v v
+------------------+ +------------------+ +------------------+
| Skia绘制命令 |---->| 合成与光栅化 |---->| GPU渲染 |
+------------------+ +------------------+ +------------------+
详细的渲染流程如下:
-
UI构建阶段:
- 用户的
build
方法返回Widget树 - Element树根据Widget树更新
- Element树创建/更新RenderObject树
- 用户的
-
布局阶段:
- 从RenderObject树的根节点开始,自上而下传递约束
- 从叶节点开始,自下而上计算并返回尺寸
-
绘制阶段:
- 创建LayerTree(图层树)
- RenderObject调用
paint
方法,将绘制命令记录到适当的Layer中
-
合成与光栅化:
- LayerTree传递给Flutter引擎
- 引擎将LayerTree转换为Skia绘制命令
- Skia执行光栅化,生成位图
-
渲染到屏幕:
- GPU将光栅化后的内容渲染到屏幕上
关键代码: 渲染流程触发
// packages/flutter/lib/src/rendering/binding.dart
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding {
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout(); // 执行布局
pipelineOwner.flushCompositingBits();// 确定哪些需要自己的层
pipelineOwner.flushPaint(); // 执行绘制
renderView.compositeFrame(); // 发送场景到GPU
}
}
底层实现: 合成帧并发送到GPU
// engine/src/flutter/flow/layers/layer_tree.cc
void LayerTree::Paint() const {
SkCanvas* canvas = frame_->SkiaCanvas();
canvas->clear(SK_ColorTRANSPARENT);
// 遍历图层树进行绘制
Layer::PrerollContext context = {
frame_->raster_cache(),
frame_->GetGrDirectContext(),
frame_->GetSceneUpdateContext(),
mutators_stack_,
checkerboard_offscreen_layers_,
};
root_layer_->Preroll(&context, frame_->GetRootTransformation());
// 绘制图层
Layer::PaintContext paint_context = {
canvas,
frame_->GetGrDirectContext(),
frame_->raster_cache(),
checkerboard_offscreen_layers_,
};
root_layer_->Paint(&paint_context);
}
1.4 Dart与C++层交互
Flutter框架中Dart与C++交互主要通过FFI(Foreign Function Interface)和Embedder API实现。
Dart与C++通信的三种主要方式:
- Method Channel: 异步通信,用于Flutter与平台特定代码交互
- Dart FFI: 直接调用本地函数,性能更高
- Native Bindings: 基于FFI的更高级别封装
Method Channel示例:
// Dart端代码
const platform = MethodChannel('samples.flutter.dev/battery');
// 调用平台特定代码
final int batteryLevel = await platform.invokeMethod('getBatteryLevel');
// Android端代码
new MethodChannel(flutterView, "samples.flutter.dev/battery").setMethodCallHandler(
(call, result) -> {
if (call.method.equals("getBatteryLevel")) {
int batteryLevel = getBatteryLevel();
result.success(batteryLevel);
} else {
result.notImplemented();
}
}
);
底层实现: Dart FFI调用原生方法
// Dart FFI调用
import 'dart:ffi';
// 定义C函数签名
typedef NativeAddFunc = Int32 Function(Int32 a, Int32 b);
// 定义对应的Dart函数签名
typedef AddFunc = int Function(int a, int b);
void main() {
// 加载动态库
final dylib = DynamicLibrary.open('path/to/library.so');
// 查找函数符号
final addFunc = dylib.lookupFunction<NativeAddFunc, AddFunc>('add');
// 调用函数
print('3 + 5 = ${addFunc(3, 5)}');
}
C++实现:
// C++实现
extern "C" {
JNIEXPORT int32_t JNICALL
Java_com_example_NativeLib_add(JNIEnv* env, jobject thiz, jint a, jint b) {
return a + b;
}
}
绘制命令如何从Dart传递到Skia:
Flutter中的绘制命令通过一系列的层(Layer)和对象将Dart层的UI描述转换为Skia的绘制命令。
// Dart层的绘制命令
canvas.drawRect(
Rect.fromLTWH(20.0, 20.0, 100.0, 100.0),
Paint()..color = Colors.blue
);
这个调用通过FFI传递到C++层:
// engine/src/flutter/lib/ui/painting/canvas.cc
void Canvas::drawRect(double left, double top, double right, double bottom,
const Paint& paint) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkiaObjectStore::DartWrappable::AssertDartObjectNotCollected(paint);
canvas_->drawRect(rect, *paint.paint());
}
最终由Skia执行实际的绘制:
// Skia内部实现(简化版)
void SkCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
// 将矩形添加到绘制列表
this->getDevice()->drawRect(rect, paint);
}
2. 核心对象模型与树结构
2.1 Widget树详解
Widget是Flutter UI的核心概念,是UI元素的不可变描述。Widget是轻量级对象,可以频繁地重建。
Widget类的核心源码:
// packages/flutter/lib/src/widgets/framework.dart
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
Element createElement();
String toStringShort() {
final String type = objectRuntimeType(this, 'Widget');
return key == null ? type : '$type-$key';
}
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
// 判断是否需要更新Element
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
Widget分为三大类:
- StatelessWidget: 无状态Widget,一旦创建不会改变
- StatefulWidget: 有状态Widget,可以在生命周期内改变
- RenderObjectWidget: 直接创建RenderObject的Widget
StatelessWidget源码:
// packages/flutter/lib/src/widgets/framework.dart
abstract class StatelessWidget extends Widget {
const StatelessWidget({ Key? key }) : super(key: key);
StatelessElement createElement() => StatelessElement(this);
Widget build(BuildContext context);
}
StatefulWidget源码:
// packages/flutter/lib/src/widgets/framework.dart
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key? key }) : super(key: key);
StatefulElement createElement() => StatefulElement(this);
State createState();
}
Widget树的构建:
Flutter应用的UI是通过嵌套Widget构建的树状结构。下面是一个简单的Widget树示例:
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Demo'),
),
body: Center(
child: Column(
children: [
Text('Hello'),
ElevatedButton(
onPressed: () {},
child: Text('Click me'),
),
],
),
),
),
)
这个Widget树的层次结构:
MaterialApp
└── Scaffold
├── AppBar
│ └── Text
└── Center
└── Column
├── Text
└── ElevatedButton
└── Text
Widget树的构建是通过各个Widget的build
方法递归完成的。例如:
class MyWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
child: Text('Hello'),
);
}
}
在内部,Flutter会调用这个build
方法来获取子Widget。
2.2 Element树与重建机制
Element是Widget的实例,负责管理Widget与RenderObject之间的关系。Element树是实际构建的UI树,而Widget树只是一个配置。
Element类的核心源码:
// packages/flutter/lib/src/widgets/framework.dart
abstract class Element extends DiagnosticableTree implements BuildContext {
Element(Widget widget)
: _widget = widget;
Widget _widget;
Widget get widget => _widget;
// 元素的状态
bool _active = false;
bool get active => _active;
// 是否需要重建
bool _dirty = true;
bool get dirty => _dirty;
// 挂载元素
void mount(Element? parent, Object? newSlot) {
_parent = parent;
_slot = newSlot;
_depth = _parent != null ? _parent!._depth + 1 : 1;
_active = true;
// 将自己添加到全局键的注册表中(如果有GlobalKey)
if (widget.key is GlobalKey) {
final GlobalKey globalKey = widget.key as GlobalKey;
_registerGlobalKey(globalKey, this);
}
// 初始化插槽
_updateInheritance();
}
// 更新Widget
void update(covariant Widget newWidget) {
// 更新widget引用
_widget = newWidget;
// 标记为需要重建
markNeedsBuild();
}
// 标记需要重建
void markNeedsBuild() {
if (!_active)
return;
if (_dirty)
return;
_dirty = true;
owner!.scheduleBuildFor(this);
}
// 重建元素
void rebuild() {
if (!_active || !_dirty)
return;
performRebuild();
}
void performRebuild();
}
Element的三个主要子类:
- ComponentElement: 用于复合Widget,如StatelessWidget和StatefulWidget
- RenderObjectElement: 与RenderObject关联的Element
- StatefulElement: 为StatefulWidget创建并管理State对象
ComponentElement源码:
// packages/flutter/lib/src/widgets/framework.dart
abstract class ComponentElement extends Element {
ComponentElement(Widget widget) : super(widget);
Element? _child;
void performRebuild() {
Widget built;
try {
// 调用build方法构建子Widget
built = build();
} catch (e, stack) {
// 处理构建过程中的错误
}
try {
// 更新子Element
_child = updateChild(_child, built, slot);
} catch (e, stack) {
// 处理更新过程中的错误
}
// 标记为不需要重建
_dirty = false;
}
Widget build();
void unmount() {
// 卸载子元素
_child = updateChild(_child, null, slot);
super.unmount();
}
}
StatefulElement源码:
// packages/flutter/lib/src/widgets/framework.dart
class StatefulElement extends ComponentElement {
StatefulElement(StatefulWidget widget)
: state = widget.createState(),
super(widget) {
state._element = this;
state._widget = widget;
}
Widget build() => state.build(this);
final State state;
void update(StatefulWidget newWidget) {
final StatefulWidget oldWidget = widget as StatefulWidget;
// 更新widget引用
super.update(newWidget);
final State state = this.state;
final bool oldWidgetWasRebuilt = _debugIsWidgetRebuilt(oldWidget);
// 更新state的widget引用
state._widget = newWidget;
// 调用state的didUpdateWidget方法
if (!oldWidgetWasRebuilt)
state.didUpdateWidget(oldWidget);
// 标记为需要重建
_dirty = true;
// 重建state
rebuild();
}
}
Element树的重建机制:
Element树的重建是通过markNeedsBuild
和performRebuild
方法协同完成的。
重建流程:
- 调用
setState
标记Element为dirty - 将Element添加到BuildOwner的脏Element列表
- 在下一帧,BuildOwner遍历脏Element列表,调用它们的
rebuild
方法 rebuild
方法调用performRebuild
,后者会构建新的Widget并更新子Element
// packages/flutter/lib/src/widgets/binding.dart
void drawFrame() {
try {
if (renderViewElement != null)
buildOwner!.buildScope(renderViewElement!);
super.drawFrame();
buildOwner!.finalizeTree();
} finally {
// ...
}
}
// packages/flutter/lib/src/widgets/framework.dart
void buildScope(Element context, [VoidCallback? callback]) {
if (callback != null) {
Timeline.startSync('Build', arguments: timelineWhitelistArguments);
try {
callback();
} finally {
Timeline.finishSync();
}
}
// 排序脏元素(按深度升序)
_dirtyElements.sort(Element._sort);
// 构建所有脏元素
int dirtyCount = _dirtyElements.length;
int index = 0;
while (index < dirtyCount) {
final Element element = _dirtyElements[index];
// 如果元素还是脏的且活跃的,则重建它
if (element._dirty && element.active) {
element.rebuild();
}
index += 1;
}
// 清空脏元素列表
_dirtyElements.clear();
}
2.3 RenderObject树与布局渲染
RenderObject树是实际负责布局和绘制的树结构,每个RenderObject对应屏幕上的一个可视元素。
RenderObject类的核心源码:
// packages/flutter/lib/src/rendering/object.dart
abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin implements HitTestTarget {
// 父级数据
ParentData? parentData;
// 约束
Constraints? _constraints;
Constraints get constraints => _constraints!;
// 是否需要布局
bool _needsLayout = true;
bool get needsLayout => _needsLayout;
// 是否需要绘制
bool _needsPaint = true;
bool get needsPaint => _needsPaint;
// 执行布局
void layout(Constraints constraints, { bool parentUsesSize = false }) {
// 检查约束是否变化
bool constraintsChanged = _constraints == null || constraints != _constraints;
// 设置新约束
_constraints = constraints;
// 如果需要布局或约束变化,执行布局
if (_needsLayout || constraintsChanged) {
_needsLayout = false;
performLayout();
markNeedsSemanticsUpdate();
}
}
// 布局方法(子类实现)
void performLayout();
// 标记需要布局
void markNeedsLayout() {
if (_needsLayout) {
return;
}
// 标记为需要布局
_needsLayout = true;
// 如果有父级,通知父级
if (parent is RenderObject) {
final RenderObject parent = this.parent! as RenderObject;
if (!_relayoutBoundary) {
parent.markNeedsLayout();
return;
}
// 如果是布局边界,将自己添加到管道所有者的_nodesNeedingLayout列表
owner!._nodesNeedingLayout.add(this);
owner!.requestVisualUpdate();
}
}
// 标记需要绘制
void markNeedsPaint() {
if (_needsPaint)
return;
_needsPaint = true;
// 将自己添加到管道所有者的_nodesNeedingPaint列表
if (isRepaintBoundary && attached) {
owner!._nodesNeedingPaint.add(this);
owner!.requestVisualUpdate();
} else if (parent is RenderObject) {
final RenderObject parent = this.parent! as RenderObject;
parent.markNeedsPaint();
}
}
// 绘制方法(子类实现)
void paint(PaintingContext context, Offset offset);
}
RenderObject有多个子类,其中最常用的是RenderBox,它处理矩形布局:
RenderBox源码:
// packages/flutter/lib/src/rendering/box.dart
abstract class RenderBox extends RenderObject {
// 尺寸
Size _size = Size.zero;
Size get size => _size;
// 布局子级
void layoutChild(RenderBox child, BoxConstraints constraints) {
child.layout(constraints, parentUsesSize: true);
}
// 子级的尺寸
Size childSize(RenderBox child) {
return child.size;
}
// 命中测试
bool hitTest(BoxHitTestResult result, { required Offset position }) {
if (_size.contains(position)) {
if (hitTestChildren(result, position: position) || hitTestSelf(position)) {
result.add(BoxHitTestEntry(this, position));
return true;
}
}
return false;
}
// 命中测试自身(子类实现)
bool hitTestSelf(Offset position) => false;
// 命中测试子级(子类实现)
bool hitTestChildren(BoxHitTestResult result, { required Offset position }) => false;
}
布局过程:
RenderObject的布局过程是从根节点自上而下进行的:
- 父节点调用子节点的
layout
方法,传递约束 - 子节点计算自己的大小,可能会根据需要调用其子节点的
layout
方法 - 子节点将自己的尺寸返回给父节点
例如,RenderFlex(用于Row和Column)的布局过程:
// packages/flutter/lib/src/rendering/flex.dart
void performLayout() {
// 首先确定主轴和交叉轴
final BoxConstraints constraints = this.constraints;
// 计算交叉轴约束
final BoxConstraints innerConstraints;
if (crossAxisAlignment == CrossAxisAlignment.stretch) {
innerConstraints = BoxConstraints.tightFor(
width: direction == Axis.horizontal ? null : constraints.maxWidth,
height: direction == Axis.horizontal ? constraints.maxHeight : null,
);
} else {
innerConstraints = BoxConstraints(
maxWidth: direction == Axis.horizontal ? double.infinity : constraints.maxWidth,
maxHeight: direction == Axis.horizontal ? constraints.maxHeight : double.infinity,
);
}
// 第一遍:确定非弹性子级的大小
double mainAxisExtent = 0.0;
double crossAxisExtent = 0.0;
RenderBox? child = firstChild;
while (child != null) {
final FlexParentData childParentData = child.parentData! as FlexParentData;
// 布局子级
child.layout(innerConstraints, parentUsesSize: true);
// 更新主轴和交叉轴的大小
final double childMainAxisExtent = _getMainAxisExtent(child);
final double childCrossAxisExtent = _getCrossAxisExtent(child);
mainAxisExtent += childMainAxisExtent;
crossAxisExtent = math.max(crossAxisExtent, childCrossAxisExtent);
child = childParentData.nextSibling;
}
// 设置自己的大小
final double allocatedSize;
if (direction == Axis.horizontal) {
size = constraints.constrain(Size(mainAxisExtent, crossAxisExtent));
allocatedSize = size.width;
} else {
size = constraints.constrain(Size(crossAxisExtent, mainAxisExtent));
allocatedSize = size.height;
}
// 第二遍:根据主轴方向和对齐方式调整子级位置
final double actualSize = allocatedSize - mainAxisExtent;
double actualSizeDelta = 0.0;
// 根据mainAxisAlignment确定子元素的位置
switch (mainAxisAlignment) {
case MainAxisAlignment.start:
leadingSpace = 0.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.end:
leadingSpace = actualSize;
betweenSpace = 0.0;
break;
case MainAxisAlignment.center:
leadingSpace = actualSize / 2.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.spaceBetween:
leadingSpace = 0.0;
betweenSpace = childCount > 1 ? actualSize / (childCount - 1) : 0.0;
break;
case MainAxisAlignment.spaceAround:
betweenSpace = childCount > 0 ? actualSize / childCount : 0.0;
leadingSpace = betweenSpace / 2.0;
break;
case MainAxisAlignment.spaceEvenly:
betweenSpace = childCount > 0 ? actualSize / (childCount + 1) : 0.0;
leadingSpace = betweenSpace;
break;
}
// 设置子级位置
double childMainPosition = leadingSpace;
child = firstChild;
while (child != null) {
final FlexParentData childParentData = child.parentData! as FlexParentData;
// 设置子级的位置
if (direction == Axis.horizontal) {
childParentData.offset = Offset(childMainPosition, 0.0);
} else {
childParentData.offset = Offset(0.0, childMainPosition);
}
childMainPosition += _getMainAxisExtent(child) + betweenSpace;
child = childParentData.nextSibling;
}
}
2.4 三棵树的协同与转换
Flutter的渲染过程涉及三棵树的协作:
- Widget树: 描述UI的配置
- Element树: 管理Widget的实例和生命周期
- RenderObject树: 处理布局和绘制
这三棵树的关系可以用下图表示:
+------------------+ +------------------+ +------------------+
| Widget树 |---->| Element树 |---->| RenderObject树 |
| (配置描述) | | (结构和状态) | | (布局和渲染) |
+------------------+ +------------------+ +------------------+
Widget → Element的转换:
通过createElement
方法,Widget创建对应的Element:
// StatelessWidget创建StatelessElement
StatelessElement createElement() => StatelessElement(this);
// StatefulWidget创建StatefulElement
StatefulElement createElement() => StatefulElement(this);
// RenderObjectWidget创建RenderObjectElement
RenderObjectElement createElement() => RenderObjectElement(this);
Element → RenderObject的转换:
RenderObjectElement通过createRenderObject
方法创建RenderObject:
// packages/flutter/lib/src/widgets/framework.dart
abstract class RenderObjectWidget extends Widget {
const RenderObjectWidget({ Key? key }) : super(key: key);
RenderObject createRenderObject(BuildContext context);
void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }
}
class RenderObjectElement extends Element {
RenderObjectElement(RenderObjectWidget widget) : super(widget);
void mount(Element? parent, Object? newSlot) {
super.mount(parent, newSlot);
_renderObject = widget.createRenderObject(this);
attachRenderObject(newSlot);
_dirty = false;
}
void update(covariant RenderObjectWidget newWidget) {
super.update(newWidget);
widget.updateRenderObject(this, renderObject);
}
}
更新流程:
当状态变化时,三棵树的更新流程如下:
- 调用
setState
,标记Element为dirty - 在下一帧,BuildOwner遍历脏Element,调用它们的
rebuild
方法 - Element重建并对比新旧Widget树,确定哪些Element需要更新或替换
- 更新RenderObject树,调用需要重新布局或绘制的RenderObject的方法
// 状态更新触发流程
void setState(VoidCallback fn) {
// 执行状态更新函数
fn();
// 标记Element需要重建
_element.markNeedsBuild();
}
// Element标记为需要重建
void markNeedsBuild() {
// 已经标记为dirty,直接返回
if (_dirty)
return;
_dirty = true;
// 将Element添加到BuildOwner的待重建列表
owner.scheduleBuildFor(this);
}
// BuildOwner调度重建
void scheduleBuildFor(Element element) {
// 将Element添加到待重建列表
_dirtyElements.add(element);
// 请求下一帧
scheduleFrame();
}
案例: Text Widget到屏幕渲染的全过程
以Text组件为例,展示从Widget到屏幕渲染的完整过程:
- 创建Widget:
Text('Hello, Flutter!')
- 创建Element:
// packages/flutter/lib/src/widgets/text.dart
RenderObjectElement createElement() => _TextElement(this);
- 创建RenderObject:
// packages/flutter/lib/src/widgets/text.dart
RenderParagraph createRenderObject(BuildContext context) {
return RenderParagraph(
_textSpan,
textDirection: textDirection,
textAlign: textAlign,
// ... 其他参数
);
}
- 布局阶段:
// packages/flutter/lib/src/rendering/paragraph.dart
void performLayout() {
// 创建文本布局器
_layoutTextWithConstraints(constraints);
// 设置大小
size = constraints.constrain(_textPainter.size);
}
- 绘制阶段:
// packages/flutter/lib/src/rendering/paragraph.dart
void paint(PaintingContext context, Offset offset) {
// 绘制文本
_textPainter.paint(context.canvas, offset);
}
这样,Text Widget最终被渲染到屏幕上,完成了从Widget到像素的转换过程。
3. 布局系统深度剖析
3.1 约束传递机制
Flutter的布局系统采用约束传递机制,这种机制从父级向子级传递约束,从子级向父级回传尺寸。
约束传递的基本过程:
父Widget → 父RenderObject → 子RenderObject → 子Widget
(传递约束) (回传尺寸)
约束的核心概念:
Flutter中有两种主要的约束类型:
- BoxConstraints: 用于矩形布局,定义了最小和最大宽高
- SliverConstraints: 用于滚动布局,包含更复杂的信息
BoxConstraints源码:
// packages/flutter/lib/src/rendering/box.dart
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)
: minWidth = size.width,
maxWidth = size.width,
minHeight = size.height,
maxHeight = size.height;
// 松散约束(只有最大尺寸限制)
const BoxConstraints.loose(Size size)
: minWidth = 0.0,
maxWidth = size.width,
minHeight = 0.0,
maxHeight = size.height;
// 扩展约束(尽可能大)
const BoxConstraints.expand({
double? width,
double? height,
}) : minWidth = width ?? double.infinity,
maxWidth = width ?? double.infinity,
minHeight = height ?? double.infinity,
maxHeight = height ?? double.infinity;
// 检查约束是否是有效的
bool get isNormalized {
return minWidth >= 0.0
&& minHeight >= 0.0
&& maxWidth >= minWidth
&& maxHeight >= minHeight;
}
// 应用约束到尺寸
Size constrain(Size size) {
Size result = Size(
clampDouble(size.width, minWidth, maxWidth),
clampDouble(size.height, minHeight, maxHeight),
);
return result;
}
}
约束传递示例:
当你创建一个Row时,它的布局过程如下:
class Row extends Flex {
Row({
Key? key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
List<Widget> children = const <Widget>[],
}) : super(
direction: Axis.horizontal,
mainAxisAlignment: mainAxisAlignment,
crossAxisAlignment: crossAxisAlignment,
children: children,
);
}
Row内部使用RenderFlex进行布局:
// packages/flutter/lib/src/rendering/flex.dart
void performLayout() {
// ... 前面的代码 ...
// 为子元素创建约束
final BoxConstraints innerConstraints = BoxConstraints(
maxWidth: direction == Axis.horizontal ? double.infinity : constraints.maxWidth,
maxHeight: direction == Axis.horizontal ? constraints.maxHeight : double.infinity,
);
// 将约束传递给子元素
RenderBox? child = firstChild;
while (child != null) {
child.layout(innerConstraints, parentUsesSize: true);
// ... 其他代码 ...
child = childParentData.nextSibling;
}
// ... 后面的代码 ...
}
约束的四种情况:
-
紧约束(Tight): minWidth=maxWidth, minHeight=maxHeight
- 例如:
BoxConstraints.tight(Size(100, 100))
- 子元素必须是指定的尺寸
- 例如:
-
松约束(Loose): minWidth=0, minHeight=0
- 例如:
BoxConstraints.loose(Size(100, 100))
- 子元素可以是任何不超过最大尺寸的尺寸
- 例如:
-
扩展约束(Expand): min=max=infinity
- 例如:
BoxConstraints.expand()
- 子元素必须尽可能大
- 例如:
-
无边界约束(Unbounded): max=infinity
- 例如:
BoxConstraints(maxWidth: double.infinity, maxHeight: double.infinity)
- 子元素可以是任意尺寸,通常在滚动视图中使用
- 例如:
3.2 布局算法详解
Flutter的布局过程是通过RenderObject的performLayout
方法实现的。不同类型的RenderObject有不同的布局算法。
主要布局算法:
- Box布局(RenderBox): 处理矩形布局
- Sliver布局(RenderSliver): 处理滚动视图中的元素
- Flex布局(RenderFlex): 处理弹性布局(Row和Column)
- Stack布局(RenderStack): 处理叠加布局
- Wrap布局(RenderWrap): 处理换行布局
Flex布局算法:
Flex布局是Flutter中最常用的布局算法之一,用于Row和Column组件。其布局过程分为几个主要步骤:
// packages/flutter/lib/src/rendering/flex.dart
void performLayout() {
// 第一步: 确定主轴和交叉轴的方向
final BoxConstraints constraints = this.constraints;
final bool horizontal = direction == Axis.horizontal;
// 第二步: 计算子元素的约束
final BoxConstraints innerConstraints;
if (crossAxisAlignment == CrossAxisAlignment.stretch) {
innerConstraints = BoxConstraints.tightFor(
width: horizontal ? null : constraints.maxWidth,
height: horizontal ? constraints.maxHeight : null,
);
} else {
innerConstraints = BoxConstraints(
maxWidth: horizontal ? double.infinity : constraints.maxWidth,
maxHeight: horizontal ? constraints.maxHeight : double.infinity,
);
}
// 第三步: 第一次遍历,确定非扩展子元素的大小和总伸缩比例
double totalFlex = 0.0;
double inflexibleSpace = 0.0;
RenderBox? child = firstChild;
while (child != null) {
final FlexParentData childParentData = child.parentData! as FlexParentData;
final int flex = childParentData.flex ?? 0;
if (flex > 0) {
totalFlex += flex;
} else {
child.layout(innerConstraints, parentUsesSize: true);
inflexibleSpace += horizontal ? child.size.width : child.size.height;
}
child = childParentData.nextSibling;
}
// 第四步: 计算扩展子元素的大小
final double availableSpace = math.max(
0.0,
(horizontal ? constraints.maxWidth : constraints.maxHeight) - inflexibleSpace,
);
double spacePerFlex = totalFlex > 0 ? availableSpace / totalFlex : 0.0;
// 第五步: 第二次遍历,布局扩展子元素
child = firstChild;
while (child != null) {
final FlexParentData childParentData = child.parentData! as FlexParentData;
final int flex = childParentData.flex ?? 0;
if (flex > 0) {
final double childMainSize = spacePerFlex * flex;
final BoxConstraints childConstraints = BoxConstraints(
minWidth: horizontal ? childMainSize : innerConstraints.minWidth,
maxWidth: horizontal ? childMainSize : innerConstraints.maxWidth,
minHeight: horizontal ? innerConstraints.minHeight : childMainSize,
maxHeight: horizontal ? innerConstraints.maxHeight : childMainSize,
);
child.layout(childConstraints, parentUsesSize: true);
}
child = childParentData.nextSibling;
}
// 第六步: 计算自身大小
double mainSize = 0.0;
double crossSize = 0.0;
child = firstChild;
while (child != null) {
final FlexParentData childParentData = child.parentData! as FlexParentData;
final double childMainSize = horizontal ? child.size.width : child.size.height;
final double childCrossSize = horizontal ? child.size.height : child.size.width;
mainSize += childMainSize;
crossSize = math.max(crossSize, childCrossSize);
child = childParentData.nextSibling;
}
// 第七步: 根据约束调整自身大小
final double containerMainSize = horizontal
? constraints.constrain(Size(mainSize, 0.0)).width
: constraints.constrain(Size(0.0, mainSize)).height;
final double containerCrossSize = horizontal
? constraints.constrain(Size(0.0, crossSize)).height
: constraints.constrain(Size(crossSize, 0.0)).width;
size = horizontal
? Size(containerMainSize, containerCrossSize)
: Size(containerCrossSize, containerMainSize);
// 第八步: 根据主轴对齐方式计算子元素位置
final double leadingSpace;
final double betweenSpace;
final int childCount = _childCount;
switch (mainAxisAlignment) {
case MainAxisAlignment.start:
leadingSpace = 0.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.end:
leadingSpace = containerMainSize - mainSize;
betweenSpace = 0.0;
break;
case MainAxisAlignment.center:
leadingSpace = (containerMainSize - mainSize) / 2.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.spaceBetween:
leadingSpace = 0.0;
betweenSpace = childCount > 1 ? (containerMainSize - mainSize) / (childCount - 1) : 0.0;
break;
case MainAxisAlignment.spaceAround:
betweenSpace = childCount > 0 ? (containerMainSize - mainSize) / childCount : 0.0;
leadingSpace = betweenSpace / 2.0;
break;
case MainAxisAlignment.spaceEvenly:
betweenSpace = childCount > 0 ? (containerMainSize - mainSize) / (childCount + 1) : 0.0;
leadingSpace = betweenSpace;
break;
}
// 第九步: 设置子元素的位置
double childMainPosition = leadingSpace;
child = firstChild;
while (child != null) {
final FlexParentData childParentData = child.parentData! as FlexParentData;
final double childMainSize = horizontal ? child.size.width : child.size.height;
final double childCrossSize = horizontal ? child.size.height : child.size.width;
double childCrossPosition;
// 根据交叉轴对齐方式计算子元素位置
switch (crossAxisAlignment) {
case CrossAxisAlignment.start:
childCrossPosition = 0.0;
break;
case CrossAxisAlignment.end:
childCrossPosition = containerCrossSize - childCrossSize;
break;
case CrossAxisAlignment.center:
childCrossPosition = (containerCrossSize - childCrossSize) / 2.0;
break;
case CrossAxisAlignment.stretch:
childCrossPosition = 0.0;
break;
case CrossAxisAlignment.baseline:
// Baseline对齐需要特殊处理
childCrossPosition = 0.0;
break;
}
// 设置子元素位置
if (horizontal) {
childParentData.offset = Offset(childMainPosition, childCrossPosition);
} else {
childParentData.offset = Offset(childCrossPosition, childMainPosition);
}
childMainPosition += childMainSize + betweenSpace;
child = childParentData.nextSibling;
}
}
Stack布局算法:
Stack布局允许子元素相互重叠,其布局算法如下:
// packages/flutter/lib/src/rendering/stack.dart
void performLayout() {
final BoxConstraints constraints = this.constraints;
_hasVisualOverflow = false;
// 计算Stack的尺寸
if (children.isEmpty) {
size = constraints.biggest;
return;
}
double width = 0.0;
double height = 0.0;
// 第一步: 布局非定位子元素,确定最小尺寸
RenderBox? child = firstChild;
while (child != null) {
final StackParentData childParentData = child.parentData! as StackParentData;
if (!childParentData.isPositioned) {
child.layout(constraints.loosen(), parentUsesSize: true);
width = math.max(width, child.size.width);
height = math.max(height, child.size.height);
}
child = childParentData.nextSibling;
}
// 第二步: 确定Stack的尺寸
size = constraints.constrain(Size(width, height));
// 第三步: 布局定位子元素
child = firstChild;
while (child != null) {
final StackParentData childParentData = child.parentData! as StackParentData;
if (childParentData.isPositioned) {
final BoxConstraints childConstraints = BoxConstraints();
// 根据定位参数计算约束
if (childParentData.left != null && childParentData.right != null) {
childConstraints.maxWidth = size.width - childParentData.left! - childParentData.right!;
} else if (childParentData.width != null) {
childConstraints.maxWidth = childParentData.width;
}
if (childParentData.top != null && childParentData.bottom != null) {
childConstraints.maxHeight = size.height - childParentData.top! - childParentData.bottom!;
} else if (childParentData.height != null) {
childConstraints.maxHeight = childParentData.height;
}
child.layout(childConstraints, parentUsesSize: true);
// 计算子元素位置
double x = 0.0;
if (childParentData.left != null) {
x = childParentData.left!;
} else if (childParentData.right != null) {
x = size.width - childParentData.right! - child.size.width;
}
double y = 0.0;
if (childParentData.top != null) {
y = childParentData.top!;
} else if (childParentData.bottom != null) {
y = size.height - childParentData.bottom! - child.size.height;
}
childParentData.offset = Offset(x, y);
} else {
// 非定位子元素位置
final BoxConstraints childConstraints;
if (alignment == null) {
childConstraints = BoxConstraints.loose(size);
} else {
childConstraints = BoxConstraints.tight(size);
}
child.layout(childConstraints, parentUsesSize: true);
// 根据alignment计算位置
childParentData.offset = alignment.resolve(textDirection).alongOffset(
size - child.size as Offset,
);
}
child = childParentData.nextSibling;
}
}
3.3 自定义布局示例
Flutter允许创建自定义布局,通过扩展RenderObject或使用CustomMultiChildLayout等方式。
自定义RenderObject:
创建自定义RenderObject需要重写performLayout
和paint
方法:
class RenderWaterfall extends RenderBox
with ContainerRenderObjectMixin<RenderBox, WaterfallParentData>,
RenderBoxContainerDefaultsMixin<RenderBox, WaterfallParentData> {
RenderWaterfall({
required int columnCount,
required double columnSpacing,
required double rowSpacing,
}) : _columnCount = columnCount,
_columnSpacing = columnSpacing,
_rowSpacing = rowSpacing;
int _columnCount;
double _columnSpacing;
double _rowSpacing;
// 设置子元素的parentData
void setupParentData(RenderBox child) {
if (child.parentData is! WaterfallParentData) {
child.parentData = WaterfallParentData();
}
}
// 自定义布局算法
void performLayout() {
if (childCount == 0) {
size = constraints.constrain(Size.zero);
return;
}
final BoxConstraints childConstraints = BoxConstraints(
maxWidth: (constraints.maxWidth - (_columnCount - 1) * _columnSpacing) / _columnCount,
);
// 每列的高度
final List<double> columnHeights = List<double>.filled(_columnCount, 0.0);
// 第一步: 布局所有子元素
RenderBox? child = firstChild;
while (child != null) {
final WaterfallParentData parentData = child.parentData! as WaterfallParentData;
// 布局子元素
child.layout(childConstraints, parentUsesSize: true);
// 找到高度最小的列
int minColumnIndex = 0;
double minColumnHeight = columnHeights[0];
for (int i = 1; i < _columnCount; i++) {
if (columnHeights[i] < minColumnHeight) {
minColumnIndex = i;
minColumnHeight = columnHeights[i];
}
}
// 计算子元素位置
final double x = minColumnIndex * (childConstraints.maxWidth + _columnSpacing);
final double y = columnHeights[minColumnIndex];
// 设置子元素位置
parentData.offset = Offset(x, y);
// 更新列高度
columnHeights[minColumnIndex] += child.size.height + _rowSpacing;
child = parentData.nextSibling;
}
// 第二步: 计算自身大小
final double height = columnHeights.reduce(math.max) - _rowSpacing;
size = constraints.constrain(Size(constraints.maxWidth, height));
}
// 绘制
void paint(PaintingContext context, Offset offset) {
defaultPaint(context, offset);
}
// 命中测试
bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
return defaultHitTestChildren(result, position: position);
}
}
// 自定义ParentData
class WaterfallParentData extends ContainerBoxParentData<RenderBox> {}
使用CustomMultiChildLayout:
Flutter也提供了更简单的方式来创建自定义布局,通过CustomMultiChildLayout:
class MyCustomLayout extends StatelessWidget {
final List<Widget> children;
MyCustomLayout({required this.children});
Widget build(BuildContext context) {
return CustomMultiChildLayout(
delegate: MyLayoutDelegate(),
children: List.generate(
children.length,
(index) => LayoutId(
id: 'child$index',
child: children[index],
),
),
);
}
}
class MyLayoutDelegate extends MultiChildLayoutDelegate {
void performLayout(Size size) {
// 获取子元素的数量
int count = 0;
while (hasChild('child$count')) {
count++;
}
// 布局逻辑
for (int i = 0; i < count; i++) {
final String id = 'child$i';
// 获取子元素的尺寸
final Size childSize = layoutChild(
id,
BoxConstraints.loose(size),
);
// 计算位置
final double x = i * childSize.width;
final double y = (i % 2) * childSize.height;
// 放置子元素
positionChild(id, Offset(x, y));
}
}
bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) {
return true;
}
}
布局约束调试:
Flutter提供了调试布局约束的工具,当遇到布局问题时非常有用:
import 'package:flutter/rendering.dart';
void main() {
// 打开布局约束调试
debugPrintMarkNeedsLayoutStacks = true;
runApp(MyApp());
}
使用LayoutBuilder查看约束:
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
print('约束: $constraints');
return Container(
width: constraints.maxWidth,
height: constraints.maxHeight,
color: Colors.blue,
);
},
)
4. 渲染系统实现细节
4.1 图层树(Layer Tree)构建
Flutter的渲染管线最终会创建一个图层树(Layer Tree),这是连接渲染逻辑和GPU绘制的桥梁。图层树由不同类型的Layer组成,每种Layer处理不同的渲染任务。
Layer类的层次结构:
Layer (基类)
├── ContainerLayer (可包含子Layer)
│ ├── OffsetLayer (应用偏移)
│ ├── ClipRectLayer (矩形裁剪)
│ ├── ClipRRectLayer (圆角矩形裁剪)
│ ├── ClipPathLayer (路径裁剪)
│ ├── TransformLayer (变换)
│ └── ShaderMaskLayer (着色器蒙版)
├── PictureLayer (包含绘制命令)
├── TextureLayer (纹理)
├── ColorFilterLayer (颜色滤镜)
└── OpacityLayer (透明度)
Layer基类源码:
// packages/flutter/lib/src/rendering/layer.dart
class Layer extends AbstractNode with DiagnosticableTreeMixin {
// 包围盒
Rect? _layerBounds;
// 是否需要重新计算包围盒
bool _needsAddToScene = true;
// 添加自身到场景
void addToScene(ui.SceneBuilder builder, [ Offset layerOffset = Offset.zero ]);
// 更新层
void updateSubtreeNeedsAddToScene() {
_needsAddToScene = true;
}
// 预绘制
void preroll(PrerollContext context, Matrix4 matrix);
}
ContainerLayer源码:
// packages/flutter/lib/src/rendering/layer.dart
class ContainerLayer extends Layer {
// 子层列表
List<Layer>? _children;
// 添加子层
void append(Layer child) {
child._remove();
child._parent = this;
_children ??= <Layer>[];
_children!.add(child);
}
// 添加到场景
void addToScene(ui.SceneBuilder builder, [ Offset layerOffset = Offset.zero ]) {
// 添加所有子层到场景
if (_children != null) {
for (final Layer child in _children!) {
child.addToScene(builder, layerOffset);
}
}
}
}
PictureLayer源码:
// packages/flutter/lib/src/rendering/layer.dart
class PictureLayer extends Layer {
PictureLayer(Rect canvasBounds)
: _canvasBounds = canvasBounds;
// 图片记录器
ui.PictureRecorder? _recorder;
// 图片
ui.Picture? _picture;
// 绘制边界
Rect _canvasBounds;
// 开始记录绘制命令
ui.Canvas beginRecording() {
_recorder = ui.PictureRecorder();
return ui.Canvas(_recorder!);
}
// 结束记录
ui.Picture endRecording() {
_picture = _recorder!.endRecording();
_recorder = null;
return _picture!;
}
// 添加到场景
void addToScene(ui.SceneBuilder builder, [ Offset layerOffset = Offset.zero ]) {
if (_picture == null)
return;
// 将图片添加到场景
builder.addPicture(layerOffset, _picture!);
}
}
图层树构建过程:
图层树的构建从RenderView.compositeFrame()
开始:
// packages/flutter/lib/src/rendering/view.dart
void compositeFrame() {
// 创建场景构建器
final ui.SceneBuilder builder = ui.SceneBuilder();
// 创建图层树
final ui.Scene scene = layer!.buildScene(builder);
// 将场景提交到引擎
window.render(scene);
// 释放资源
scene.dispose();
}
在Layer.buildScene()
中,会遍历整个图层树:
// packages/flutter/lib/src/rendering/layer.dart
ui.Scene buildScene(ui.SceneBuilder builder) {
// 更新图层树
updateSubtreeNeedsAddToScene();
// 添加自身到场景
addToScene(builder);
// 构建场景
return builder.build();
}
实际示例: 构建图层树:
以一个带有阴影的容器为例,其图层树构建过程:
// Widget代码
Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 5,
offset: Offset(0, 3),
),
],
),
child: Text('Hello'),
)
对应的渲染过程:
- 创建一个PictureLayer绘制阴影
- 创建一个PictureLayer绘制容器背景
- 创建一个PictureLayer绘制文本
- 将这些PictureLayer添加到ContainerLayer中
4.2 绘制过程与合成
Flutter的绘制过程从RenderObject的paint
方法开始,经过PaintingContext转换为图层树,最终由引擎进行合成。
RenderObject绘制:
RenderObject的paint
方法负责将自身绘制到PaintingContext:
// 以RenderParagraph为例(Text的渲染对象)
// packages/flutter/lib/src/rendering/paragraph.dart
void paint(PaintingContext context, Offset offset) {
if (_needsClipping) {
// 如果需要裁剪,创建一个裁剪层
context.pushClipRect(needsCompositing, offset, Offset.zero & size, _paint);
} else {
// 直接绘制文本
_paint(context, offset);
}
}
void _paint(PaintingContext context, Offset offset) {
// 获取画布
final Canvas canvas = context.canvas;
// 设置文本绘制位置
_textPainter.paint(canvas, offset);
// 如果有选择区域,绘制选择区域
if (_selectionRects != null) {
for (final TextBox textBox in _selectionRects!) {
canvas.drawRect(
textBox.toRect().shift(offset),
_selectionPaint,
);
}
}
}
PaintingContext源码:
PaintingContext是RenderObject和Canvas之间的桥梁,它管理绘制操作和图层创建:
// packages/flutter/lib/src/rendering/object.dart
class PaintingContext extends ClipContext {
// 创建绘制上下文
PaintingContext(this._containerLayer, this.estimatedBounds);
// 容器层
final ContainerLayer _containerLayer;
// 绘制区域
final Rect estimatedBounds;
// 画布
Canvas? _canvas;
// 当前记录器
PictureLayer? _recorder;
// 获取画布
Canvas get canvas {
if (_canvas == null) {
_startRecording();
}
return _canvas!;
}
// 开始记录绘制命令
void _startRecording() {
_recorder = PictureLayer(estimatedBounds);
_canvas = _recorder!.beginRecording();
_containerLayer.append(_recorder!);
}
// 停止记录
void stopRecordingIfNeeded() {
if (_recorder != null) {
_recorder!.endRecording();
_recorder = null;
_canvas = null;
}
}
// 创建裁剪层
void pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter) {
if (needsCompositing) {
// 如果需要合成,创建新的裁剪层
final ClipRectLayer clipLayer = ClipRectLayer(clipRect: clipRect.shift(offset));
pushLayer(clipLayer, painter, offset);
} else {
// 否则直接裁剪画布
canvas.save();
canvas.clipRect(clipRect.shift(offset));
painter(this, offset);
canvas.restore();
}
}
// 创建变换层
void pushTransform(bool needsCompositing, Offset offset, Matrix4 transform, PaintingContextCallback painter) {
if (needsCompositing) {
// 如果需要合成,创建新的变换层
final Matrix4 effectiveTransform = Matrix4.translationValues(offset.dx, offset.dy, 0.0)
..multiply(transform)
..translate(-offset.dx, -offset.dy);
final TransformLayer transformLayer = TransformLayer(transform: effectiveTransform);
pushLayer(transformLayer, painter, offset);
} else {
// 否则直接变换画布
canvas.save();
canvas.translate(offset.dx, offset.dy);
canvas.transform(transform.storage);
canvas.translate(-offset.dx, -offset.dy);
painter(this, offset);
canvas.restore();
}
}
// 创建新层
void pushLayer(ContainerLayer childLayer, PaintingContextCallback painter, Offset offset) {
// 停止当前记录
stopRecordingIfNeeded();
// 将子层添加到容器层
_containerLayer.append(childLayer);
// 创建新的绘制上下文
final PaintingContext childContext = PaintingContext(childLayer, estimatedBounds);
// 调用绘制回调
painter(childContext, offset);
// 停止子上下文的记录
childContext.stopRecordingIfNeeded();
}
}
合成过程:
合成过程是将图层树转换为GPU可以渲染的命令序列。这个过程在Flutter引擎中完成:
// engine/src/flutter/flow/compositor_context.cc
void CompositorContext::BeginFrame(fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
// 初始化帧状态
if (raster_thread_merger) {
raster_thread_merger_ = raster_thread_merger;
}
// 记录帧开始时间
const auto now = fml::TimePoint::Now();
const auto frame_time = time_converter_.ToFrameTime(now);
frame_times_.push_back(frame_time);
}
void CompositorContext::EndFrame(ScopedFrame& frame, bool end_raster_thread_merger) {
// 释放帧资源
if (raster_thread_merger_ && end_raster_thread_merger) {
raster_thread_merger_->EndFrame();
raster_thread_merger_ = nullptr;
}
// 更新统计信息
const auto now = fml::TimePoint::Now();
while (!frame_times_.empty()) {
const auto& oldest_frame_time = frame_times_.front();
if (now - oldest_frame_time < kFrameTimeThreshold) {
break;
}
frame_times_.pop_front();
}
}
std::unique_ptr<ScopedFrame> CompositorContext::AcquireFrame(
GrDirectContext* gr_context,
SkCanvas* canvas,
ExternalViewEmbedder* view_embedder,
const SkMatrix& root_surface_transformation,
bool instrumentation_enabled) {
// 创建一个新帧
return std::make_unique<ScopedFrame>(*this, gr_context, canvas, view_embedder,
root_surface_transformation,
instrumentation_enabled);
}
渲染管线优化:
Flutter引擎包含多种优化技术,提高渲染性能:
- 图层合并: 尽可能减少图层数量
- 渲染缓存: 缓存不变的渲染结果
- 裁剪优化: 只渲染可见区域
- 纹理压缩: 减少GPU内存占用
渲染缓存源码:
// packages/flutter/lib/src/rendering/proxy_box.dart
class RenderRepaintBoundary extends RenderProxyBox {
bool get isRepaintBoundary => true;
void paint(PaintingContext context, Offset offset) {
// 当作为重绘边界时,会创建新的图层
context.pushLayer(OffsetLayer(), super.paint, offset);
}
}
在底层,这会触发渲染缓存机制:
// engine/src/flutter/flow/raster_cache.cc
bool RasterCache::Prepare(PrerollContext* context,
Layer* layer,
const SkMatrix& matrix) {
// 检查是否应该缓存
if (!IsCacheable(layer, matrix)) {
return false;
}
// 创建缓存条目
auto entry = Entry{
.layer = layer,
.matrix = matrix,
};
// 检查是否已经在缓存中
auto it = cache_.find(entry);
if (it != cache_.end()) {
// 更新命中计数
it->second.access_count++;
// 检查是否需要重新渲染
if (it->second.access_count >= kMinimumAccessCount) {
it->second.image = RasterizeSurface(context, layer, matrix);
}
} else {
// 添加到缓存
cache_[entry] = {
.access_count = 1,
.image = nullptr,
};
}
return true;
}
sk_sp<SkImage> RasterCache::RasterizeSurface(PrerollContext* context,
Layer* layer,
const SkMatrix& matrix) {
// 创建离屏渲染目标
SkRect bounds = layer->paint_bounds();
SkImageInfo image_info = SkImageInfo::MakeN32Premul(
bounds.width(), bounds.height());
// 创建Surface
auto surface = SkSurface::MakeRenderTarget(
context->gr_context, SkBudgeted::kYes, image_info);
// 获取画布
auto canvas = surface->getCanvas();
// 设置变换
canvas->translate(-bounds.left, -bounds.top);
canvas->concat(matrix);
// 绘制图层
PaintContext paint_context = {
.canvas = canvas,
.gr_context = context->gr_context,
.view_embedder = context->view_embedder,
.raster_cache = this,
};
layer->Paint(&paint_context);
// 生成图像
return surface->makeImageSnapshot();
}
4.3 光栅化与GPU渲染
Flutter的渲染管线最后阶段是光栅化和GPU渲染,这是将图层树转换为像素的过程。
光栅化过程:
光栅化是将矢量图形转换为像素点阵的过程。在Flutter中,这一过程由Skia引擎负责:
// engine/src/flutter/flow/layers/layer_tree.cc
void LayerTree::Preroll(CompositorContext::ScopedFrame& frame) {
// 预处理阶段,计算各层的包围盒
frame.context().beginFrame(nullptr);
// 准备上下文
PrerollContext context = {
frame.gr_context(), // GrContext
frame.view_embedder(), // ExternalViewEmbedder
&frame.context().raster_cache(), // RasterCache
false, // subtree_can_inherit_opacity
};
// 预处理根层
root_layer_->Preroll(&context, frame.root_surface_transformation());
}
void LayerTree::Paint(CompositorContext::ScopedFrame& frame) {
// 光栅化阶段,将图层树绘制到画布
if (root_layer_->needs_painting()) {
// 准备上下文
PaintContext context = {
frame.canvas(), // canvas
frame.gr_context(), // gr_context
frame.view_embedder(), // view_embedder
&frame.context().raster_cache(), // raster_cache
};
// 绘制根层
root_layer_->Paint(&context);
}
}
在Skia内部,光栅化过程涉及以下步骤:
- 几何处理: 将矢量描述转换为三角形网格
- 着色: 计算每个像素的颜色值
- 纹理映射: 将纹理应用到几何图形上
- 混合: 处理透明度和混合模式
GPU渲染:
光栅化后的数据最终会传递给GPU进行渲染。Flutter使用Skia的GPU后端(GrContext)来与GPU交互:
// engine/src/flutter/shell/common/rasterizer.cc
void Rasterizer::Draw(std::unique_ptr<FramePipeline::Iterator> pipeline) {
// 处理所有待渲染的帧
while (pipeline->HasNextFrame()) {
// 获取下一帧
auto frame = pipeline->GetNextFrame();
// 如果帧无效,跳过
if (frame.IsEmpty()) {
continue;
}
// 绘制当前帧
DrawToSurface(frame);
// 通知帧已完成
pipeline->UnregisterFrame();
}
}
void Rasterizer::DrawToSurface(FramePipeline::FrameResult& frame) {
// 准备Surface
auto surface = surface_producer_->ProduceSurface(frame.GetFrameSize());
if (!surface) {
return;
}
// 获取画布
auto canvas = surface->getCanvas();
// 获取GrContext
auto gr_context = surface_producer_->GetContext();
// 创建合成上下文
CompositorContext::ScopedFrame compositor_frame =
compositor_context_.AcquireFrame(gr_context, canvas, nullptr,
surface_producer_->GetRootTransformation());
// 预处理图层树
frame.GetLayerTree().Preroll(compositor_frame);
// 绘制图层树
frame.GetLayerTree().Paint(compositor_frame);
// 提交Surface
surface_producer_->PresentSurface(std::move(surface));
}
渲染管线优化:
Flutter引擎包含多种优化技术,提高渲染性能:
- 图层合并: 尽可能减少图层数量
- 渲染缓存: 缓存不变的渲染结果
- 裁剪优化: 只渲染可见区域
- 纹理压缩: 减少GPU内存占用
渲染缓存源码:
// packages/flutter/lib/src/rendering/proxy_box.dart
class RenderRepaintBoundary extends RenderProxyBox {
bool get isRepaintBoundary => true;
void paint(PaintingContext context, Offset offset) {
// 当作为重绘边界时,会创建新的图层
context.pushLayer(OffsetLayer(), super.paint, offset);
}
}
在底层,这会触发渲染缓存机制:
// engine/src/flutter/flow/raster_cache.cc
bool RasterCache::Prepare(PrerollContext* context,
Layer* layer,
const SkMatrix& matrix) {
// 检查是否应该缓存
if (!IsCacheable(layer, matrix)) {
return false;
}
// 创建缓存条目
auto entry = Entry{
.layer = layer,
.matrix = matrix,
};
// 检查是否已经在缓存中
auto it = cache_.find(entry);
if (it != cache_.end()) {
// 更新命中计数
it->second.access_count++;
// 检查是否需要重新渲染
if (it->second.access_count >= kMinimumAccessCount) {
it->second.image = RasterizeSurface(context, layer, matrix);
}
} else {
// 添加到缓存
cache_[entry] = {
.access_count = 1,
.image = nullptr,
};
}
return true;
}
sk_sp<SkImage> RasterCache::RasterizeSurface(PrerollContext* context,
Layer* layer,
const SkMatrix& matrix) {
// 创建离屏渲染目标
SkRect bounds = layer->paint_bounds();
SkImageInfo image_info = SkImageInfo::MakeN32Premul(
bounds.width(), bounds.height());
// 创建Surface
auto surface = SkSurface::MakeRenderTarget(
context->gr_context, SkBudgeted::kYes, image_info);
// 获取画布
auto canvas = surface->getCanvas();
// 设置变换
canvas->translate(-bounds.left, -bounds.top);
canvas->concat(matrix);
// 绘制图层
PaintContext paint_context = {
.canvas = canvas,
.gr_context = context->gr_context,
.view_embedder = context->view_embedder,
.raster_cache = this,
};
layer->Paint(&paint_context);
// 生成图像
return surface->makeImageSnapshot();
}
5. 状态管理与更新机制
Flutter的状态管理是其响应式UI框架的核心。本节将深入分析Flutter状态更新的完整链路,BuildOwner的作用,以及setState的内部实现。
5.1 状态更新完整链路
Flutter的状态更新涉及一系列精心设计的步骤,从setState
调用到屏幕刷新的完整链路如下:
状态更新链路图:
setState() → markNeedsBuild() → scheduleBuildFor() →
scheduleFrame() → [VSync信号] → handleBeginFrame() → handleDrawFrame() →
drawFrame() → buildScope() → Element.rebuild() → build() →
flushLayout() → flushPaint() → compositeFrame() → render()
1. 状态变更触发:
当调用setState
时,会触发状态更新的起点:
// packages/flutter/lib/src/widgets/framework.dart
void setState(VoidCallback fn) {
// 断言不在build方法中调用setState
assert(_debugLifecycleState != _StateLifecycle.build);
// 断言Widget已挂载
assert(_debugLifecycleState != _StateLifecycle.defunct);
// 执行状态更新函数
fn();
// 标记Element需要重建
_element!.markNeedsBuild();
}
2. 标记Element需要重建:
markNeedsBuild
方法将Element标记为dirty并安排重建:
// packages/flutter/lib/src/widgets/framework.dart
void markNeedsBuild() {
// 如果已经被标记为dirty,直接返回
if (_dirty)
return;
// 检查Element是否还活跃
if (!_active)
return;
// 标记为dirty
_dirty = true;
// 将Element添加到BuildOwner的待重建列表
owner!.scheduleBuildFor(this);
}
3. BuildOwner调度重建:
scheduleBuildFor
将Element添加到脏元素列表:
// packages/flutter/lib/src/widgets/framework.dart
void scheduleBuildFor(Element element) {
// 只有处于clean状态的Element才需要加入重建队列
if (!element._dirty) {
_dirtyElements.add(element);
element._dirty = true;
}
// 请求新的一帧
scheduleFrame();
}
4. 请求新的一帧:
scheduleFrame
通知Flutter引擎在下一个VSync信号到来时绘制新帧:
// packages/flutter/lib/src/scheduler/binding.dart
void scheduleFrame() {
if (_hasScheduledFrame || !_framesEnabled)
return;
// 向引擎请求新帧
ui.PlatformDispatcher.instance.scheduleFrame();
_hasScheduledFrame = true;
}
5. 处理帧回调:
当VSync信号到来时,Flutter引擎会调用handleBeginFrame
和handleDrawFrame
:
// packages/flutter/lib/src/scheduler/binding.dart
('vm:notify-debugger-on-exception')
void handleBeginFrame(Duration? rawTimeStamp) {
// 记录帧开始时间
Timeline.startSync('Frame', arguments: timelineWhitelistArguments);
// 处理动画和其他瞬态回调
_schedulerPhase = SchedulerPhase.transientCallbacks;
final Map<int, _FrameCallbackEntry> callbacks = _transientCallbacks;
_transientCallbacks = <int, _FrameCallbackEntry>{};
callbacks.forEach((int id, _FrameCallbackEntry callbackEntry) {
if (!_removedIds.contains(id))
_invokeFrameCallback(callbackEntry.callback, _currentFrameTimeStamp!, callbackEntry.debugStack);
});
// 进入微任务阶段
_schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
('vm:notify-debugger-on-exception')
void handleDrawFrame() {
// 处理持久性回调(例如构建和布局)
_schedulerPhase = SchedulerPhase.persistentCallbacks;
for (final FrameCallback callback in _persistentCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!, null);
// 处理帧结束回调
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
final List<FrameCallback> localPostFrameCallbacks =
List<FrameCallback>.from(_postFrameCallbacks);
_postFrameCallbacks.clear();
for (final FrameCallback callback in localPostFrameCallbacks)
_invokeFrameCallback(callback, _currentFrameTimeStamp!, null);
// 回到空闲状态
_schedulerPhase = SchedulerPhase.idle;
}
6. Widget绑定绘制帧:
在持久性回调阶段,WidgetsBinding.drawFrame
被调用:
// packages/flutter/lib/src/widgets/binding.dart
void drawFrame() {
try {
// 首先重建所有标记为dirty的元素
if (renderViewElement != null)
buildOwner!.buildScope(renderViewElement!);
// 然后进行布局和绘制
super.drawFrame();
// 最后完成树构建
buildOwner!.finalizeTree();
} finally {
// ...
}
}
7. BuildOwner构建作用域:
buildScope
方法会重建所有dirty元素:
// packages/flutter/lib/src/widgets/framework.dart
void buildScope(Element context, [VoidCallback? callback]) {
if (callback != null) {
Timeline.startSync('Build', arguments: timelineWhitelistArguments);
try {
callback();
} finally {
Timeline.finishSync();
}
}
// 按照深度排序脏元素,从根到叶
_dirtyElements.sort(Element._sort);
// 重建所有脏元素
int dirtyCount = _dirtyElements.length;
int index = 0;
while (index < dirtyCount) {
final Element element = _dirtyElements[index];
if (element._dirty && element.active) {
element.rebuild();
}
index += 1;
}
// 清空脏元素列表
_dirtyElements.clear();
}
8. Element重建:
每个dirty元素都会调用rebuild
方法进行重建:
// packages/flutter/lib/src/widgets/framework.dart
void rebuild() {
if (!_active || !_dirty)
return;
// 执行重建
performRebuild();
}
9. StatefulElement重建:
对于StatefulElement,performRebuild
会调用State的build方法:
// packages/flutter/lib/src/widgets/framework.dart
void performRebuild() {
// 调用state.build获取新的Widget
final Widget built = build();
// 更新子Element树
_child = updateChild(_child, built, slot);
// 标记为不再dirty
_dirty = false;
}
Widget build() => state.build(this);
10. 渲染阶段:
完成Widget树重建后,进行渲染阶段:
// packages/flutter/lib/src/rendering/binding.dart
void drawFrame() {
// 执行布局
pipelineOwner.flushLayout();
// 确定合成位
pipelineOwner.flushCompositingBits();
// 执行绘制
pipelineOwner.flushPaint();
// 合成帧并发送到GPU
renderView.compositeFrame();
}
11. 布局与绘制:
在flushLayout
和flushPaint
中,所有标记为需要布局或绘制的RenderObject会被处理:
// packages/flutter/lib/src/rendering/object.dart
void flushLayout() {
// 处理所有需要布局的RenderObject
while (_nodesNeedingLayout.isNotEmpty) {
final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
_nodesNeedingLayout = <RenderObject>[];
// 按照深度排序,从根到叶
dirtyNodes.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
// 对每个节点执行布局
for (final RenderObject node in dirtyNodes) {
if (node._needsLayout && node.owner == this)
node._layoutWithoutResize();
}
}
}
void flushPaint() {
// 处理所有需要绘制的RenderObject
final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
_nodesNeedingPaint = <RenderObject>[];
// 按照深度排序,从叶到根
dirtyNodes.sort((RenderObject a, RenderObject b) => b.depth - a.depth);
// 对每个节点执行绘制
for (final RenderObject node in dirtyNodes) {
if (node._needsPaint && node.owner == this) {
if (node._layer == null || node._layer!.attached)
PaintingContext.repaintCompositedChild(node);
else
node._skippedPaintingOnLayer();
}
}
}
12. 合成与渲染:
最后,compositeFrame
将绘制结果合成为一个场景并发送到GPU:
// packages/flutter/lib/src/rendering/view.dart
void compositeFrame() {
// 创建场景构建器
final ui.SceneBuilder builder = ui.SceneBuilder();
// 构建场景
final ui.Scene scene = layer!.buildScene(builder);
// 发送场景到GPU
ui.window.render(scene);
// 释放场景资源
scene.dispose();
}
整个状态更新链路展示了Flutter从状态变化到屏幕更新的完整流程,体现了其响应式UI框架的精妙设计。
5.2 BuildOwner与更新调度
BuildOwner是Flutter状态管理的核心协调器,负责管理Element的构建和更新。
BuildOwner的核心职责:
- 维护和调度脏Element的重建
- 管理焦点树
- 处理语义更新
- 协调整体UI更新流程
BuildOwner的源码结构:
// packages/flutter/lib/src/widgets/framework.dart
class BuildOwner {
BuildOwner({this.onBuildScheduled, this.focusManager});
// 构建调度回调
final VoidCallback? onBuildScheduled;
// 焦点管理器
final FocusManager? focusManager;
// 脏元素列表
final List<Element> _dirtyElements = <Element>[];
// 是否禁用构建
bool _scheduledBuildPhase = false;
// 标记元素需要重建
void scheduleBuildFor(Element element) {
if (element._dirty)
return;
_dirtyElements.add(element);
element._dirty = true;
// 调度构建
if (onBuildScheduled != null && !_scheduledBuildPhase) {
_scheduledBuildPhase = true;
onBuildScheduled!();
}
}
// 执行构建
void buildScope(Element context, [VoidCallback? callback]) {
// 执行传入的回调
if (callback != null) {
callback();
}
// 排序脏元素
_dirtyElements.sort(Element._sort);
// 重建所有脏元素
int index = 0;
while (index < _dirtyElements.length) {
final Element element = _dirtyElements[index];
if (element._dirty && element.active) {
element.rebuild();
}
index += 1;
}
// 清空脏元素列表
_dirtyElements.clear();
_scheduledBuildPhase = false;
}
// 完成树构建
void finalizeTree() {
// 处理未发送的状态变更
for (final Element element in _dirtyElements) {
if (element.dirty && element.active) {
element.rebuild();
}
}
_dirtyElements.clear();
// 更新焦点
focusManager?.updateGlobalFocusCount();
// 更新语义
_semanticsOwner?.sendSemanticsUpdate();
}
}
BuildOwner与WidgetsBinding的关系:
BuildOwner是由WidgetsBinding创建和管理的:
// packages/flutter/lib/src/widgets/binding.dart
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
// BuildOwner实例
BuildOwner? _buildOwner;
BuildOwner? get buildOwner => _buildOwner;
// 初始化
void initInstances() {
super.initInstances();
// 创建BuildOwner
_buildOwner = BuildOwner(
onBuildScheduled: _handleBuildScheduled,
focusManager: focusManager,
);
}
// 处理构建调度
void _handleBuildScheduled() {
// 确保我们会收到下一帧的回调
ensureVisualUpdate();
}
}
更新调度流程:
- 当调用
setState
时,关联的Element被标记为dirty - Element调用
BuildOwner.scheduleBuildFor
将自己添加到脏元素列表 - BuildOwner触发
onBuildScheduled
回调,实际上是_handleBuildScheduled
_handleBuildScheduled
调用ensureVisualUpdate
,它会调用scheduleFrame
scheduleFrame
请求一个新的帧- 在下一个VSync信号到来时,引擎调用
handleBeginFrame
和handleDrawFrame
- 在
handleDrawFrame
中,WidgetsBinding.drawFrame
被调用 drawFrame
调用buildOwner.buildScope
重建所有脏元素
BuildOwner的高效设计:
- 批量处理: 将所有脏元素收集起来一次性处理,避免重复构建
- 深度排序: 按照深度排序脏元素,确保父元素在子元素之前重建
- 延迟构建: 直到下一帧才进行构建,避免不必要的中间状态
- 构建边界: 仅重建标记为脏的元素及其子树,而不是整个UI树
5.3 setState内部实现
setState
是Flutter状态管理的核心API,它触发UI更新的整个过程。让我们深入分析它的内部实现。
State类的设计:
// packages/flutter/lib/src/widgets/framework.dart
abstract class State<T extends StatefulWidget> {
// 当前widget引用
T get widget => _widget as T;
T _widget;
// 关联的Element
StatefulElement? _element;
// 状态生命周期
_StateLifecycle _debugLifecycleState = _StateLifecycle.created;
// setState方法
void setState(VoidCallback fn) {
// 各种断言检查
assert(() {
if (_debugLifecycleState == _StateLifecycle.defunct) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('setState() called after dispose()'),
// 更多错误信息...
]);
}
if (_debugLifecycleState == _StateLifecycle.build) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('setState() called during build'),
// 更多错误信息...
]);
}
return true;
}());
// 执行状态更新函数
fn();
// 标记Element需要重建
_element!.markNeedsBuild();
}
// 构建方法(子类必须实现)
Widget build(BuildContext context);
// 生命周期方法
void initState() { }
void didUpdateWidget(covariant T oldWidget) { }
void dispose() { }
}
setState的核心实现:
setState
方法的实现非常简洁:
void setState(VoidCallback fn) {
// 执行状态更新函数
fn();
// 标记Element需要重建
_element!.markNeedsBuild();
}
它做了两件事:
- 执行传入的回调函数,更新状态变量
- 调用关联Element的
markNeedsBuild
方法,触发UI更新
markNeedsBuild的实现:
// packages/flutter/lib/src/widgets/framework.dart
void markNeedsBuild() {
// 如果已经标记为dirty,直接返回
if (_dirty)
return;
// 检查Element是否还活跃
if (!_active)
return;
// 标记为dirty
_dirty = true;
// 将Element添加到BuildOwner的待重建列表
owner!.scheduleBuildFor(this);
}
setState的调用约束:
从源码中的断言可以看出,setState
有以下调用约束:
- 不能在
build
方法中调用 - 不能在
dispose
后调用 - 必须在有效的State生命周期中调用
setState与Element的关联:
State和Element的关联在StatefulElement的构造函数中建立:
// packages/flutter/lib/src/widgets/framework.dart
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
super(widget) {
// 将state与element关联
_state._element = this;
_state._widget = widget;
}
状态更新的细节:
当调用setState
时,实际的Widget更新发生在下一帧的build
阶段:
// packages/flutter/lib/src/widgets/framework.dart
class StatefulElement extends ComponentElement {
// ...
Widget build() {
// 调用state.build获取新的Widget树
return _state.build(this);
}
void performRebuild() {
// 先调用didUpdateWidget(如果需要)
if (_didUpdateWidget) {
_state.didUpdateWidget(oldWidget);
_didUpdateWidget = false;
}
// 然后进行标准的重建流程
super.performRebuild();
}
}
异步setState的处理:
Flutter允许在异步上下文中调用setState
:
Future<void> fetchData() async {
final response = await http.get('https://api.example.com/data');
setState(() {
_data = jsonDecode(response.body);
});
}
这是因为Element和State的生命周期是框架管理的,只要State对象存在且与活跃的Element关联,就可以调用setState
触发更新。
批量更新的实现:
多次调用setState
会被批量处理:
// 示例: 连续调用setState
void updateMultipleTimes() {
setState(() => _counter += 1);
setState(() => _text = 'Updated');
setState(() => _color = Colors.red);
}
这是因为markNeedsBuild
只是将Element添加到脏列表,实际重建发生在下一帧,所以多次更新会合并为一次重建。
总结:
setState
是Flutter状态管理的核心机制,它通过简洁的API隐藏了复杂的状态更新流程。通过深入理解其内部实现,可以更好地掌握Flutter的响应式UI模型,编写高效的状态管理代码。
6. 事件处理与手势识别
Flutter的事件处理系统是一套精心设计的机制,用于接收、分发和处理用户输入。本节将深入分析Flutter事件传递路径、手势识别竞技场和事件分发处理机制。
6.1 事件传递路径
Flutter的事件系统从底层平台事件开始,经过多层转换和分发,最终到达具体的Widget。整个过程如下:
事件传递完整路径:
平台事件(Android/iOS) → Engine(C++) → Window(Dart) →
GestureBinding → HitTestResult → RenderObject树(自上而下) →
事件分发(自下而上) → GestureDetector/Listener → 回调函数
1. 从平台到Flutter引擎:
平台原生事件(如触摸、键盘)首先由操作系统捕获,然后传递给Flutter引擎:
// engine/src/flutter/shell/platform/android/android_shell_holder.cc (Android)
void AndroidShellHolder::DispatchPointerDataPacket(
std::unique_ptr<flutter::PointerDataPacket> packet) {
// 将指针事件传递给引擎
engine_->DispatchPointerDataPacket(std::move(packet));
}
// engine/src/flutter/lib/ui/window/window.cc
void Window::DispatchPointerDataPacket(const PointerDataPacket& packet) {
// 引擎将事件转换为Dart可理解的格式,并传递给Dart代码
std::vector<uint8_t> data = packet.data();
UIDartState::Current()->OnPointerDataPacket(data);
}
2. 从引擎到Dart层:
事件到达Dart层后,由Window
类接收并传递给GestureBinding
:
// packages/flutter/lib/src/gestures/binding.dart
void onPointerDataPacket(ui.PointerDataPacket packet) {
// 将指针数据转换为PointerEvent对象
final List<PointerEvent> pointerEvents = PointerEventConverter.expand(
packet.data,
_pointerState.devicePixelRatio,
);
// 分发事件
if (pointerEvents.isNotEmpty)
_handlePointerEvents(pointerEvents);
}
3. 命中测试:
事件到达后,Flutter需要确定哪些对象应该接收事件,这通过命中测试(Hit Testing)实现:
// packages/flutter/lib/src/gestures/binding.dart
void _handlePointerEvents(Iterable<PointerEvent> events) {
// 处理每个事件
for (final PointerEvent event in events) {
// 为每个指针跟踪事件历史
final HitTestResult? hitTestResult = _hitTests[event.pointer];
// 如果是按下事件,执行命中测试
if (event is PointerDownEvent) {
// 创建一个新的命中测试结果
final HitTestResult result = HitTestResult();
// 执行命中测试,从根开始
hitTest(result, event.position);
// 存储此指针的命中测试结果
_hitTests[event.pointer] = result;
// 将命中测试结果转发给其他处理器
dispatchEvent(event, result);
} else if (hitTestResult != null) {
// 对于其他事件,使用已保存的命中测试结果
dispatchEvent(event, hitTestResult);
}
}
}
4. 命中测试从根RenderObject开始:
命中测试从RenderView
(根RenderObject)开始,向下遍历整个RenderObject树:
// packages/flutter/lib/src/rendering/view.dart
bool hitTest(HitTestResult result, { required Offset position }) {
// 首先将自己添加到命中测试结果
if (child != null)
child!.hitTest(BoxHitTestResult.wrap(result), position: position);
// 总是返回true,因为这是根视图
return true;
}
5. RenderObject树的命中测试:
命中测试递归地遍历RenderObject树,每个RenderObject决定是否命中以及是否继续传递给子节点:
// packages/flutter/lib/src/rendering/box.dart
bool hitTest(BoxHitTestResult result, { required Offset position }) {
// 检查位置是否在此RenderBox的边界内
if (_size.contains(position)) {
// 首先测试子节点
if (hitTestChildren(result, position: position) || hitTestSelf(position)) {
// 如果命中,将自己添加到结果中
result.add(BoxHitTestEntry(this, position));
return true;
}
}
return false;
}
6. 自定义RenderObject的命中测试示例:
RenderPointerListener
是一个专门处理指针事件的RenderObject:
// packages/flutter/lib/src/rendering/proxy_box.dart
bool hitTestSelf(Offset position) => behavior != HitTestBehavior.deferToChild;
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
if (behavior == HitTestBehavior.opaque)
return false;
return super.hitTestChildren(result, position: position);
}
7. 事件分发:
一旦命中测试完成,事件会按照命中测试结果的相反顺序分发:
// packages/flutter/lib/src/gestures/binding.dart
void dispatchEvent(PointerEvent event, HitTestResult hitTestResult) {
// 按照命中测试结果的相反顺序分发事件(从叶子节点到根节点)
for (final HitTestEntry entry in hitTestResult.path) {
try {
entry.target.handleEvent(event.transformed(entry.transform), entry);
} catch (exception, stack) {
// 处理错误...
}
}
}
8. 在RenderObject中处理事件:
每个RenderObject可以选择如何处理事件:
// packages/flutter/lib/src/rendering/proxy_box.dart
void handleEvent(PointerEvent event, HitTestEntry entry) {
// RenderPointerListener处理指针事件
assert(debugHandleEvent(event, entry));
if (onPointerDown != null && event is PointerDownEvent)
onPointerDown!(event);
if (onPointerMove != null && event is PointerMoveEvent)
onPointerMove!(event);
if (onPointerUp != null && event is PointerUpEvent)
onPointerUp!(event);
if (onPointerCancel != null && event is PointerCancelEvent)
onPointerCancel!(event);
if (onPointerSignal != null && event is PointerSignalEvent)
onPointerSignal!(event);
}
9. 从RenderObject到Widget:
事件从RenderObject传递到Widget层,通常通过如下方式:
// packages/flutter/lib/src/widgets/gesture_detector.dart
class RenderSemanticsGestureHandler extends RenderProxyBox {
// ...
void handleEvent(PointerEvent event, HitTestEntry entry) {
// 将事件转发给回调
if (onTap != null && event is PointerUpEvent)
onTap!();
// ...
}
}
10. GestureDetector的实现:
最终,用户通过GestureDetector等Widget接收事件:
// packages/flutter/lib/src/widgets/gesture_detector.dart
class GestureDetector extends StatelessWidget {
// ...
Widget build(BuildContext context) {
// 创建手势识别器
final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};
// 配置点击识别器
if (onTap != null || onTapDown != null || /* ... */) {
gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
() => TapGestureRecognizer(debugOwner: this),
(TapGestureRecognizer instance) {
instance
..onTapDown = onTapDown
..onTapUp = onTapUp
..onTap = onTap
// ...
},
);
}
// 创建RawGestureDetector
Widget result = RawGestureDetector(
gestures: gestures,
behavior: behavior,
child: child,
);
return result;
}
}
通过这个完整的事件传递路径,Flutter能够精确地将用户输入传递给正确的Widget,实现响应式的交互体验。
6.2 手势识别竞技场
Flutter的手势识别系统采用"竞技场"模式,允许多个手势识别器竞争同一事件流,最终确定哪个识别器"胜出"。
手势竞技场的核心概念:
- 手势识别器(GestureRecognizer): 识别特定模式的触摸序列
- 竞技场(Arena): 管理识别器之间的竞争
- 仲裁机制: 决定哪个识别器最终处理手势
GestureArena源码:
// packages/flutter/lib/src/gestures/arena.dart
class GestureArenaManager {
// 存储每个指针ID对应的竞技场
final Map<int, GestureArenaEntry> _arenas = <int, GestureArenaEntry>{};
// 添加成员到竞技场
GestureArenaEntry add(int pointer, GestureArenaMember member) {
// 获取或创建竞技场
GestureArenaEntry? entry = _arenas[pointer];
if (entry == null) {
entry = GestureArenaEntry._(this, pointer);
_arenas[pointer] = entry;
}
// 添加成员
entry._members.add(member);
return entry;
}
// 关闭竞技场,不再接受新成员
void close(int pointer) {
final GestureArenaEntry? entry = _arenas[pointer];
if (entry == null)
return;
entry._isOpen = false;
_tryToResolveArena(pointer, entry);
}
// 某个成员宣布胜出
void sweep(int pointer) {
final GestureArenaEntry? entry = _arenas[pointer];
if (entry == null)
return;
// 如果只有一个成员,它直接胜出
if (entry._members.length == 1) {
final GestureArenaMember member = entry._members.first;
entry._members.clear();
_arenas.remove(pointer);
member.acceptGesture(pointer);
return;
}
// 否则,拒绝所有成员
if (entry._members.isNotEmpty) {
final List<GestureArenaMember> members = List<GestureArenaMember>.from(entry._members);
entry._members.clear();
_arenas.remove(pointer);
for (final GestureArenaMember member in members)
member.rejectGesture(pointer);
}
}
// 尝试解决竞技场
void _tryToResolveArena(int pointer, GestureArenaEntry entry) {
// 如果竞技场关闭且只有一个成员,它胜出
if (!entry._isOpen && entry._members.length == 1) {
final GestureArenaMember member = entry._members.first;
entry._members.clear();
_arenas.remove(pointer);
member.acceptGesture(pointer);
return;
}
// 如果竞技场关闭且没有成员,移除竞技场
if (!entry._isOpen && entry._members.isEmpty) {
_arenas.remove(pointer);
}
}
}
手势识别器的基类:
// packages/flutter/lib/src/gestures/recognizer.dart
abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableTreeMixin {
// 添加指针
void addPointer(PointerDownEvent event) {
// 注册到竞技场
_entries[event.pointer] = GestureBinding.instance.gestureArena.add(event.pointer, this);
}
// 开始跟踪指针
void startTrackingPointer(int pointer, [Matrix4? transform]) {
GestureBinding.instance.pointerRouter.addRoute(pointer, handleEvent, transform);
}
// 停止跟踪指针
void stopTrackingPointer(int pointer) {
GestureBinding.instance.pointerRouter.removeRoute(pointer, handleEvent);
}
// 处理事件(子类实现)
void handleEvent(PointerEvent event);
// 竞技场回调:接受手势
void acceptGesture(int pointer) { }
// 竞技场回调:拒绝手势
void rejectGesture(int pointer) { }
}
手势识别器示例 - TapGestureRecognizer:
// packages/flutter/lib/src/gestures/tap.dart
class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
// 事件回调
GestureTapDownCallback? onTapDown;
GestureTapUpCallback? onTapUp;
GestureTapCallback? onTap;
GestureTapCancelCallback? onTapCancel;
// 状态变量
bool _sentTapDown = false;
bool _wonArenaForPrimaryPointer = false;
Offset? _finalPosition;
// 处理指针按下事件
void handlePrimaryPointer(PointerEvent event) {
if (event is PointerUpEvent) {
_finalPosition = event.position;
// 检查是否胜出
_checkUp();
} else if (event is PointerCancelEvent) {
_reset();
}
}
// 竞技场回调:接受手势
void acceptGesture(int pointer) {
if (pointer == primaryPointer) {
_wonArenaForPrimaryPointer = true;
_checkUp();
}
}
// 竞技场回调:拒绝手势
void rejectGesture(int pointer) {
if (pointer == primaryPointer) {
// 发送取消事件
if (_sentTapDown) {
if (onTapCancel != null)
onTapCancel!();
}
_reset();
}
}
// 检查是否应该触发点击事件
void _checkUp() {
if (_wonArenaForPrimaryPointer && _finalPosition != null) {
// 如果胜出且有最终位置,触发点击事件
if (onTapUp != null) {
onTapUp!(TapUpDetails(
kind: getKindForPointer(primaryPointer!),
globalPosition: _finalPosition!,
localPosition: _finalPosition!, // 简化版本
));
}
if (onTap != null)
onTap!();
_reset();
}
}
// 重置状态
void _reset() {
_sentTapDown = false;
_wonArenaForPrimaryPointer = false;
_finalPosition = null;
}
}
竞争解决机制:
- 明确放弃: 某个识别器可以显式放弃竞争
// packages/flutter/lib/src/gestures/recognizer.dart
void resolve(GestureDisposition disposition) {
final List<int> localKeys = List<int>.from(_entries.keys);
for (final int pointer in localKeys) {
final GestureArenaEntry? entry = _entries[pointer];
if (entry != null) {
entry.resolve(disposition);
}
}
}
- 优先级: 有些识别器具有更高的优先级
// 例如,SingleChildScrollView的识别器可以在垂直滚动方向上获得优先权
void _handleDragStart(DragStartDetails details) {
// 如果是垂直方向滚动,则更有可能获胜
if (widget.scrollDirection == Axis.vertical) {
// ...
}
}
- 竞技场关闭: 当指针抬起时,竞技场关闭并强制解决
// packages/flutter/lib/src/gestures/binding.dart
void _handlePointerEventImmediately(PointerEvent event) {
// ...
if (event is PointerUpEvent || event is PointerCancelEvent) {
// 关闭竞技场
gestureArena.close(event.pointer);
} else if (event is PointerDownEvent) {
// 为此指针创建竞技场
gestureArena.open(event.pointer);
}
// ...
}
手势竞技场的优势:
- 消除歧义: 处理复杂的多手势情况,如区分点击和拖动
- 延迟决策: 可以等待更多信息再做决定
- 层次结构: 允许父子Widget都有机会处理手势
- 动态适应: 可以根据手势的发展改变决策
这种竞技场机制使Flutter能够处理复杂的手势交互,同时保持代码的模块化和可扩展性。
6.3 事件分发与处理
事件分发是Flutter事件系统的核心机制,它确保事件能够正确地传递给相应的处理者。
事件分发的核心组件:
- PointerRouter: 管理指针事件的路由
- HitTestResult: 存储命中测试的结果
- GestureBinding: 协调整个事件系统
PointerRouter源码:
// packages/flutter/lib/src/gestures/pointer_router.dart
class PointerRouter {
// 存储每个指针ID对应的路由表
final Map<int, Map<PointerRoute, Matrix4?>> _routeMap = <int, Map<PointerRoute, Matrix4?>>{};
// 添加路由
void addRoute(int pointer, PointerRoute route, [Matrix4? transform]) {
final Map<PointerRoute, Matrix4?> routes = _routeMap.putIfAbsent(
pointer,
() => <PointerRoute, Matrix4?>{},
);
routes[route] = transform;
}
// 移除路由
void removeRoute(int pointer, PointerRoute route) {
final Map<PointerRoute, Matrix4?>? routes = _routeMap[pointer];
if (routes != null) {
routes.remove(route);
if (routes.isEmpty)
_routeMap.remove(pointer);
}
}
// 分发事件
void route(PointerEvent event) {
final Map<PointerRoute, Matrix4?>? routes = _routeMap[event.pointer];
if (routes == null)
return;
// 复制路由表,防止在迭代过程中修改
final List<PointerRoute> callbackRoutes = routes.keys.toList();
final List<Matrix4?> transforms = routes.values.toList();
// 调用所有路由
for (int i = 0; i < callbackRoutes.length; i++) {
try {
callbackRoutes[i](
event.transformed(transforms[i])
);
} catch (exception, stack) {
// 处理错误...
}
}
}
}
事件分发流程:
- 接收原始事件:
// packages/flutter/lib/src/gestures/binding.dart
void onPointerDataPacket(ui.PointerDataPacket packet) {
// 将原始数据转换为PointerEvent对象
final List<PointerEvent> pointerEvents = PointerEventConverter.expand(
packet.data,
_pointerState.devicePixelRatio,
);
// 处理事件
if (pointerEvents.isNotEmpty)
_handlePointerEvents(pointerEvents);
}
- 执行命中测试:
// packages/flutter/lib/src/gestures/binding.dart
void _handlePointerEvents(Iterable<PointerEvent> events) {
for (final PointerEvent event in events) {
if (event is PointerDownEvent) {
// 执行命中测试
final HitTestResult result = HitTestResult();
hitTest(result, event.position);
_hitTests[event.pointer] = result;
}
// 分发事件
dispatchEvent(event, _hitTests[event.pointer]);
}
}
- 分发事件到命中对象:
// packages/flutter/lib/src/gestures/binding.dart
void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) {
// 首先路由事件到直接监听者
_pointerRouter.route(event);
// 然后路由到命中测试结果
if (hitTestResult != null) {
for (final HitTestEntry entry in hitTestResult.path) {
entry.target.handleEvent(event.transformed(entry.transform), entry);
}
}
}
渲染对象中的事件处理:
渲染对象实现handleEvent
方法来处理事件:
// packages/flutter/lib/src/rendering/proxy_box.dart
class RenderPointerListener extends RenderProxyBox {
// 事件回调
PointerDownEventListener? onPointerDown;
PointerMoveEventListener? onPointerMove;
PointerUpEventListener? onPointerUp;
PointerCancelEventListener? onPointerCancel;
void handleEvent(PointerEvent event, BoxHitTestEntry entry) {
assert(debugHandleEvent(event, entry));
// 根据事件类型调用相应回调
if (onPointerDown != null && event is PointerDownEvent)
onPointerDown!(event);
if (onPointerMove != null && event is PointerMoveEvent)
onPointerMove!(event);
if (onPointerUp != null && event is PointerUpEvent)
onPointerUp!(event);
if (onPointerCancel != null && event is PointerCancelEvent)
onPointerCancel!(event);
}
}
手势识别器的事件处理:
手势识别器通过PointerRouter接收事件:
// packages/flutter/lib/src/gestures/recognizer.dart
abstract class OneSequenceGestureRecognizer extends GestureRecognizer {
final Map<int, GestureArenaEntry> _entries = <int, GestureArenaEntry>{};
// 添加指针并开始跟踪
void addPointer(PointerDownEvent event) {
// 注册到竞技场
_entries[event.pointer] = GestureBinding.instance.gestureArena.add(event.pointer, this);
// 开始跟踪指针
startTrackingPointer(event.pointer);
}
// 处理事件
void handleEvent(PointerEvent event) {
if (event is PointerDownEvent) {
// 处理按下事件
handlePrimaryPointer(event);
} else if (event.pointer == primaryPointer) {
// 处理主指针的事件
handlePrimaryPointer(event);
} else {
// 处理辅助指针的事件
handleSecondaryPointer(event);
}
}
}
Listener和GestureDetector的关系:
Listener
直接处理低级指针事件,而GestureDetector
使用手势识别器处理高级手势:
// packages/flutter/lib/src/widgets/gesture_detector.dart
class GestureDetector extends StatelessWidget {
Widget build(BuildContext context) {
// 创建手势识别器
final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};
// 配置识别器...
// 创建RawGestureDetector
Widget result = RawGestureDetector(
gestures: gestures,
behavior: behavior,
child: child,
);
// 额外的Listener配置
if (onPointerDown != null ||
onPointerMove != null ||
onPointerUp != null ||
onPointerCancel != null) {
result = Listener(
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onPointerCancel: onPointerCancel,
child: result,
);
}
return result;
}
}
自定义事件处理示例:
以下是实现自定义手势识别器的示例:
class CustomTapGestureRecognizer extends TapGestureRecognizer {
// 自定义属性
final Duration maxTime;
CustomTapGestureRecognizer({
required Object debugOwner,
this.maxTime = const Duration(milliseconds: 300),
}) : super(debugOwner: debugOwner);
// 记录按下时间
DateTime? _downTime;
void handlePrimaryPointer(PointerEvent event) {
if (event is PointerDownEvent) {
_downTime = DateTime.now();
} else if (event is PointerUpEvent) {
// 检查时间间隔
final timeDiff = DateTime.now().difference(_downTime!);
if (timeDiff > maxTime) {
// 如果超过最大时间,放弃竞技场
resolve(GestureDisposition.rejected);
return;
}
}
// 调用父类处理方法
super.handlePrimaryPointer(event);
}
}
通过这种分层的事件处理机制,Flutter可以灵活地处理各种复杂的交互场景,同时保持代码的清晰和模块化。
7. 动画系统实现
Flutter的动画系统是构建流畅、精美用户界面的重要组成部分。本节将深入分析Flutter动画系统的核心实现,包括Ticker机制、动画控制器和动画插值计算。
7.1 Ticker与SchedulerBinding
Flutter的动画系统基于"tick"机制,即屏幕刷新时的回调通知。这一机制由Ticker和SchedulerBinding共同实现。
Ticker的核心概念:
Ticker是一个简单的计时器,它在每一帧到来时调用回调函数。Ticker本身不驱动动画,而是提供了时间信号。
Ticker源码:
// packages/flutter/lib/src/scheduler/ticker.dart
class Ticker {
// 构造函数
Ticker(this._onTick, { this.debugLabel });
// 帧回调函数
final TickerCallback _onTick;
// 调试标签
final String? debugLabel;
// 开始时间
Duration? _startTime;
// 是否启用
bool _active = false;
// 是否暂停
bool _muted = false;
// 启动Ticker
void start() {
// 已经启动则直接返回
if (_active)
return;
// 标记为活跃
_active = true;
// 如果未静音,注册帧回调
if (!_muted)
_startTicker();
}
// 停止Ticker
void stop({ bool canceled = false }) {
if (!_active)
return;
// 标记为非活跃
_active = false;
// 如果已注册帧回调,取消注册
if (_animationId != null) {
SchedulerBinding.instance.cancelFrameCallbackWithId(_animationId!);
_animationId = null;
}
}
// 内部ID
int? _animationId;
// 启动内部Ticker
void _startTicker() {
assert(_active);
assert(_animationId == null);
// 注册帧回调
_animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick);
// 记录启动时间
_startTime ??= SchedulerBinding.instance.currentFrameTime;
}
// 每帧回调
void _tick(Duration timeStamp) {
// 取消当前的帧回调ID
_animationId = null;
// 如果暂停或停止,直接返回
if (!_active || _muted)
return;
// 计算流逝的时间
final Duration elapsedDuration = timeStamp - (_startTime ?? timeStamp);
// 调用回调
_onTick(elapsedDuration);
// 如果仍然活跃且未静音,注册下一帧回调
if (_active && !_muted)
_animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick);
}
}
SchedulerBinding的角色:
SchedulerBinding是连接Flutter引擎和框架的纽带之一,负责处理VSync信号和帧回调。
// packages/flutter/lib/src/scheduler/binding.dart
mixin SchedulerBinding on BindingBase implements ServicesBinding {
// 帧回调列表
final List<FrameCallback> _persistentCallbacks = <FrameCallback>[];
// 瞬态回调映射
final Map<int, _FrameCallbackEntry> _transientCallbacks = <int, _FrameCallbackEntry>{};
// 下一个回调ID
int _nextCallbackId = 0;
// 调度帧回调
int scheduleFrameCallback(FrameCallback callback, { bool rescheduling = false }) {
// 生成回调ID
final int id = _nextCallbackId += 1;
// 添加到瞬态回调映射
_transientCallbacks[id] = _FrameCallbackEntry(callback, rescheduling);
// 请求新的一帧
if (_hasScheduledFrame)
return id;
if (handleScheduleFrame != null) {
handleScheduleFrame!();
} else {
scheduleFrame();
}
return id;
}
// 取消帧回调
void cancelFrameCallbackWithId(int id) {
_transientCallbacks.remove(id);
}
// 处理帧开始
void handleBeginFrame(Duration? rawTimeStamp) {
Timeline.startSync('Frame', arguments: timelineWhitelistArguments);
// 设置当前帧时间戳
_currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
// 如果处于空闲状态,处理瞬态回调
if (_schedulerPhase == SchedulerPhase.idle) {
_schedulerPhase = SchedulerPhase.transientCallbacks;
try {
_invokeTransientFrameCallbacks(_currentFrameTimeStamp!);
} finally {
_schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
}
}
// 调用瞬态帧回调
void _invokeTransientFrameCallbacks(Duration timeStamp) {
final Map<int, _FrameCallbackEntry> callbacks = _transientCallbacks;
_transientCallbacks = <int, _FrameCallbackEntry>{};
callbacks.forEach((int id, _FrameCallbackEntry callbackEntry) {
if (!_removedIds.contains(id)) {
_invokeFrameCallback(callbackEntry.callback, timeStamp, callbackEntry.debugStack);
}
});
}
}
TickerProvider的作用:
TickerProvider是一个抽象接口,用于创建Ticker。通常由StatefulWidget的State实现,以便在widget生命周期内管理Ticker。
// packages/flutter/lib/src/scheduler/ticker.dart
abstract class TickerProvider {
// 创建Ticker
Ticker createTicker(TickerCallback onTick);
}
// 单Ticker提供者
mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider {
Ticker? _ticker;
Ticker createTicker(TickerCallback onTick) {
assert(_ticker == null);
_ticker = Ticker(onTick, debugLabel: 'created by ${widget.runtimeType}');
return _ticker!;
}
void dispose() {
// 确保Ticker在State销毁时也被销毁
_ticker?.dispose();
super.dispose();
}
}
Ticker与动画的连接:
Ticker为动画系统提供了时间信号,动画控制器使用这些信号来驱动动画状态更新:
// AnimationController构造时需要TickerProvider
AnimationController controller = AnimationController(
vsync: this, // 提供Ticker
duration: Duration(seconds: 1),
);
// 内部创建Ticker
_ticker = vsync.createTicker(_tick);
// 在每一帧回调中更新动画值
void _tick(Duration elapsed) {
// 更新动画值
value = _simulation.x(elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond);
// 如果动画结束,停止Ticker
if (_simulation.isDone(elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond)) {
stop();
}
}
7.2 动画控制器与驱动
AnimationController是Flutter动画系统的核心控制器,负责管理动画的状态和进度。
AnimationController源码:
// packages/flutter/lib/src/animation/animation_controller.dart
class AnimationController extends Animation<double>
with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
// 构造函数
AnimationController({
double? value,
this.duration,
this.reverseDuration,
this.debugLabel,
this.lowerBound = 0.0,
this.upperBound = 1.0,
this.animationBehavior = AnimationBehavior.normal,
required TickerProvider vsync,
}) : _direction = _AnimationDirection.forward {
// 创建Ticker
_ticker = vsync.createTicker(_tick);
// 设置初始值
_internalSetValue(value ?? lowerBound);
}
// Ticker引用
late final Ticker _ticker;
// 动画值
double _value = 0.0;
// 动画方向
_AnimationDirection _direction;
// 动画状态
AnimationStatus _status = AnimationStatus.dismissed;
// 动画模拟器(控制动画曲线)
Simulation? _simulation;
// 获取动画值
double get value => _value;
// 设置动画值
set value(double newValue) {
// 停止当前动画
stop();
// 设置新值
_internalSetValue(newValue);
// 通知监听器
notifyListeners();
_checkStatusChanged();
}
// 内部设置值
void _internalSetValue(double newValue) {
// 确保值在范围内
_value = clampDouble(newValue, lowerBound, upperBound);
}
// 正向运行动画
TickerFuture forward({ double? from }) {
// 设置起始值
if (from != null)
value = from;
// 设置方向和状态
_direction = _AnimationDirection.forward;
if (value == upperBound) {
_status = AnimationStatus.completed;
return TickerFuture.complete();
}
// 如果动画被禁用,直接完成
if (_ticker.muted) {
_status = AnimationStatus.forward;
value = upperBound;
_status = AnimationStatus.completed;
return TickerFuture.complete();
}
// 设置状态
_status = AnimationStatus.forward;
// 创建动画模拟器
return _animateToInternal(upperBound);
}
// 反向运行动画
TickerFuture reverse({ double? from }) {
// 设置起始值
if (from != null)
value = from;
// 设置方向和状态
_direction = _AnimationDirection.reverse;
if (value == lowerBound) {
_status = AnimationStatus.dismissed;
return TickerFuture.complete();
}
// 如果动画被禁用,直接完成
if (_ticker.muted) {
_status = AnimationStatus.reverse;
value = lowerBound;
_status = AnimationStatus.dismissed;
return TickerFuture.complete();
}
// 设置状态
_status = AnimationStatus.reverse;
// 创建动画模拟器
return _animateToInternal(lowerBound);
}
// 动画到指定值
TickerFuture animateTo(double target, { Duration? duration, Curve curve = Curves.linear }) {
// 设置方向
if (target > value) {
_direction = _AnimationDirection.forward;
} else if (target < value) {
_direction = _AnimationDirection.reverse;
}
// 设置状态
_status = (_direction == _AnimationDirection.forward)
? AnimationStatus.forward
: AnimationStatus.reverse;
// 创建动画模拟器
return _animateToInternal(target, duration: duration, curve: curve);
}
// 内部动画实现
TickerFuture _animateToInternal(double target, { Duration? duration, Curve curve = Curves.linear }) {
// 停止当前动画
stop();
// 如果已经到达目标,直接返回
if (target == value)
return TickerFuture.complete();
// 计算动画时长
Duration calculatedDuration;
if (duration == null) {
final double range = upperBound - lowerBound;
final double remainingFraction = (target - value).abs() / range;
calculatedDuration = this.duration! * remainingFraction;
} else {
calculatedDuration = duration;
}
// 创建模拟器
_simulation = _InterpolationSimulation(value, target, calculatedDuration, curve);
// 启动Ticker
return _ticker.start();
}
// 每帧回调
void _tick(Duration elapsed) {
// 计算动画值
_value = _simulation!.x(elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond);
// 如果动画结束
if (_simulation!.isDone(elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond)) {
_status = (_direction == _AnimationDirection.forward)
? AnimationStatus.completed
: AnimationStatus.dismissed;
stop();
}
// 通知监听器
notifyListeners();
}
// 停止动画
void stop({ bool canceled = false }) {
// 停止Ticker
_ticker.stop(canceled: canceled);
// 清除模拟器
_simulation = null;
}
// 释放资源
void dispose() {
// 释放Ticker
_ticker.dispose();
super.dispose();
}
}
动画驱动器的类型:
Flutter的动画系统使用物理模拟(Simulation)来驱动动画。主要的模拟器包括:
- _InterpolationSimulation: 基于插值的简单模拟器
- SpringSimulation: 弹簧物理模拟
- GravitySimulation: 重力物理模拟
- FrictionSimulation: 摩擦物理模拟
_InterpolationSimulation源码:
// packages/flutter/lib/src/animation/animation_controller.dart
class _InterpolationSimulation extends Simulation {
_InterpolationSimulation(
this._begin,
this._end,
Duration duration,
this._curve,
) : _durationInSeconds = duration.inMicroseconds.toDouble() / Duration.microsecondsPerSecond;
final double _begin;
final double _end;
final double _durationInSeconds;
final Curve _curve;
double x(double timeInSeconds) {
final double t = clampDouble(timeInSeconds / _durationInSeconds, 0.0, 1.0);
if (t == 0.0)
return _begin;
if (t == 1.0)
return _end;
return _begin + (_end - _begin) * _curve.transform(t);
}
double dx(double timeInSeconds) {
final double t = clampDouble(timeInSeconds / _durationInSeconds, 0.0, 1.0);
if (t == 0.0 || t == 1.0)
return 0.0;
return (_end - _begin) * _curve.derivativeAt(t) / _durationInSeconds;
}
bool isDone(double timeInSeconds) => timeInSeconds >= _durationInSeconds;
}
SpringSimulation源码:
// packages/flutter/lib/src/physics/spring_simulation.dart
class SpringSimulation extends Simulation {
SpringSimulation(
SpringDescription spring,
double start,
double end,
double velocity, {
Tolerance tolerance = Tolerance.defaultTolerance,
}) : _spring = spring,
_solution = _SpringSolution(spring, start - end, velocity),
_type = _SpringType.underDamped,
_endPosition = end,
super(tolerance: tolerance) {
// ...
}
final SpringDescription _spring;
final _SpringSolution _solution;
final _SpringType _type;
final double _endPosition;
double x(double time) => _endPosition + _solution.position(time);
double dx(double time) => _solution.velocity(time);
bool isDone(double time) {
return _solution.position(time).abs() < tolerance.distance
&& _solution.velocity(time).abs() < tolerance.velocity;
}
}
动画状态与通知:
AnimationController实现了Animation接口,提供了状态通知机制:
// packages/flutter/lib/src/animation/animation.dart
abstract class Animation<T> extends Listenable {
// 动画值
T get value;
// 动画状态
AnimationStatus get status;
// 添加状态监听器
void addStatusListener(AnimationStatusListener listener);
// 移除状态监听器
void removeStatusListener(AnimationStatusListener listener);
}
动画控制器的使用:
// 创建动画控制器
final AnimationController controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
// 正向运行
controller.forward();
// 反向运行
controller.reverse();
// 动画到指定值
controller.animateTo(0.5, duration: Duration(milliseconds: 500));
// 重复动画
controller.repeat();
// 添加监听器
controller.addListener(() {
setState(() {
// 使用controller.value更新UI
});
});
// 添加状态监听器
controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// 动画完成时的处理
}
});
7.3 动画插值与曲线
动画插值是将动画进度(0.0到1.0)转换为具体值的过程。Flutter提供了丰富的插值机制和曲线函数。
Tween源码:
Tween定义了起点和终点,负责将动画进度转换为具体类型的值:
// packages/flutter/lib/src/animation/tween.dart
class Tween<T extends num> extends Animatable<T> {
// 构造函数
Tween({ required this.begin, required this.end });
// 起点值
final T begin;
// 终点值
final T end;
// 插值计算
T transform(double t) {
if (t == 0.0)
return begin;
if (t == 1.0)
return end;
return begin + (end - begin) * t as T;
}
// 获取动画对象
Animation<T> animate(Animation<double> parent) {
return _AnimatedEvaluation<T>(parent, this);
}
}
ColorTween源码:
ColorTween是特定类型的Tween,用于颜色过渡:
// packages/flutter/lib/src/animation/tween.dart
class ColorTween extends Tween<Color?> {
ColorTween({ required Color? begin, required Color? end }) : super(begin: begin, end: end);
Color? transform(double t) {
if (begin == null && end == null)
return null;
if (begin == null)
return Color.lerp(begin, end, t);
if (end == null)
return Color.lerp(begin, end, t);
return Color.lerp(begin, end, t);
}
}
曲线函数(Curve)源码:
曲线函数定义了动画进度的变化方式,使动画具有不同的效果:
// packages/flutter/lib/src/animation/curves.dart
abstract class Curve {
const Curve();
// 转换进度值
double transform(double t);
// 获取在特定点的导数
double derivativeAt(double t) {
return (transform(t + _kGoldenRatio) - transform(t)) / _kGoldenRatio;
}
// 创建动画区间
Curve get flipped => FlippedCurve(this);
}
// 线性曲线
class _Linear extends Curve {
const _Linear._();
double transform(double t) => t;
}
// 缓入曲线
class _EaseInCurve extends Curve {
const _EaseInCurve();
double transform(double t) => t * t;
}
// 缓出曲线
class _EaseOutCurve extends Curve {
const _EaseOutCurve();
double transform(double t) => t * (2.0 - t);
}
// 缓入缓出曲线
class _EaseInOutCurve extends Curve {
const _EaseInOutCurve();
double transform(double t) {
if (t < 0.5)
return 2.0 * t * t;
return -1.0 + (4.0 - 2.0 * t) * t;
}
}
预定义曲线:
Flutter预定义了许多常用曲线:
// packages/flutter/lib/src/animation/curves.dart
abstract class Curves {
// 线性曲线
static const Curve linear = _Linear._();
// 缓入
static const Curve easeIn = _EaseInCurve();
// 缓出
static const Curve easeOut = _EaseOutCurve();
// 缓入缓出
static const Curve easeInOut = _EaseInOutCurve();
// 弹性曲线
static const Curve elasticIn = ElasticInCurve();
static const Curve elasticOut = ElasticOutCurve();
static const Curve elasticInOut = ElasticInOutCurve();
// 弹跳曲线
static const Curve bounceIn = BounceInCurve();
static const Curve bounceOut = BounceOutCurve();
static const Curve bounceInOut = BounceInOutCurve();
}
CurvedAnimation源码:
CurvedAnimation将曲线应用于动画:
// packages/flutter/lib/src/animation/animations.dart
class CurvedAnimation extends Animation<double> with AnimationWithParentMixin<double> {
// 构造函数
CurvedAnimation({
required this.parent,
required this.curve,
this.reverseCurve,
});
// 父动画
final Animation<double> parent;
// 正向曲线
Curve curve;
// 反向曲线
Curve? reverseCurve;
// 获取动画值
double get value {
final Curve activeCurve = _useForwardCurve ? curve : (reverseCurve ?? curve.flipped);
final double t = parent.value;
if (t == 0.0 || t == 1.0) {
return t;
}
return activeCurve.transform(t);
}
// 当前是否使用正向曲线
bool get _useForwardCurve {
return parent.status != AnimationStatus.reverse
&& parent.status != AnimationStatus.dismissed;
}
}
使用动画插值:
// 创建动画控制器
final controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
);
// 应用曲线
final Animation<double> curvedAnimation = CurvedAnimation(
parent: controller,
curve: Curves.easeInOut,
);
// 创建颜色动画
final Animation<Color?> colorAnimation = ColorTween(
begin: Colors.blue,
end: Colors.red,
).animate(curvedAnimation);
// 创建尺寸动画
final Animation<double> sizeAnimation = Tween<double>(
begin: 50.0,
end: 200.0,
).animate(curvedAnimation);
// 使用动画值
Container(
width: sizeAnimation.value,
height: sizeAnimation.value,
color: colorAnimation.value,
)
自定义插值:
可以创建自定义Tween实现特殊插值:
class MyCustomTween extends Tween<MyCustomObject> {
MyCustomTween({ required MyCustomObject begin, required MyCustomObject end })
: super(begin: begin, end: end);
MyCustomObject transform(double t) {
return MyCustomObject(
size: begin.size + (end.size - begin.size) * t,
color: Color.lerp(begin.color, end.color, t),
rotation: begin.rotation + (end.rotation - begin.rotation) * t,
);
}
}
自定义曲线:
可以创建自定义曲线实现特殊动画效果:
class BackAndForthCurve extends Curve {
double transform(double t) {
if (t < 0.5) {
return t * 2.0; // 0.0 到 1.0
} else {
return 2.0 - t * 2.0; // 1.0 到 0.0
}
}
}
通过这些核心机制,Flutter的动画系统可以实现各种复杂的动画效果,同时保持高性能和流畅度。动画系统的模块化设计也使开发者可以轻松扩展和自定义动画行为。
8. 应用启动与渲染流程
8.1 引擎初始化过程
Flutter的引擎初始化是一个复杂的过程,涉及到多个系统的配置和启动。
Flutter引擎初始化流程:
-
平台特定入口点:
- Android:
FlutterActivity
或FlutterFragment
- iOS:
FlutterViewController
- Android:
-
创建引擎实例:
// engine/src/flutter/shell/common/shell.cc std::unique_ptr<Shell> Shell::Create( TaskRunners task_runners, Settings settings, Shell::CreateCallback on_create_platform_view, Shell::CreateCallback on_create_rasterizer) { // 创建DartVM auto vm = DartVMRef::Create(settings); // 创建Shell实例 auto shell = std::unique_ptr<Shell>(new Shell(std::move(vm), std::move(task_runners), settings)); // 创建平台视图 shell->CreatePlatformView(on_create_platform_view); // 创建光栅器 shell->CreateRasterizer(on_create_rasterizer); return shell; }
-
初始化Dart虚拟机:
// engine/src/flutter/runtime/dart_vm.cc DartVM::DartVM(std::shared_ptr<const DartVMData> vm_data) : vm_data_(std::move(vm_data)) { // 配置Dart VM选项 std::vector<const char*> args; for (const auto& arg : vm_data_->settings().dart_flags) { args.push_back(arg.c_str()); } // 初始化Dart VM char* error = Dart_Initialize( vm_data_->settings().vm_snapshot_data->GetMapping(), vm_data_->settings().isolate_snapshot_data ? vm_data_->settings().isolate_snapshot_data->GetMapping() : nullptr, DartVMFlags::FlagsToDartFlags(args).data(), args.size(), nullptr, nullptr, nullptr, nullptr, nullptr); }
-
初始化渲染系统:
// engine/src/flutter/shell/common/rasterizer.cc Rasterizer::Rasterizer(TaskRunners task_runners) : task_runners_(std::move(task_runners)), weak_factory_(this) { // 初始化合成上下文 compositor_context_ = std::make_unique<CompositorContext>(); }
-
设置平台消息通道:
// engine/src/flutter/shell/platform/android/platform_view_android.cc void PlatformViewAndroid::RegisterWithJava( JNIEnv* env, jclass clazz, jmethodID on_platform_message_method) { // 注册Java回调 on_platform_message_method_ = on_platform_message_method; // 设置平台消息处理程序 SetupPlatformMessageHandlers(); }
8.2 平台通道与插件系统
Flutter通过平台通道(Platform Channels)与原生平台通信,这是Flutter插件系统的基础。
平台通道类型:
- MethodChannel: 用于方法调用
- EventChannel: 用于事件流
- BasicMessageChannel: 用于基本消息传递
平台通道的实现:
// packages/flutter/lib/src/services/platform_channel.dart
class MethodChannel {
/// 构造函数
const MethodChannel(this.name, [this.codec = const StandardMethodCodec()]);
/// 通道名称
final String name;
/// 编解码器
final MethodCodec codec;
/// 调用平台方法
Future<T?> invokeMethod<T>(String method, [dynamic arguments]) async {
final ByteData? result = await ServicesBinding.instance!.defaultBinaryMessenger
.send(name, codec.encodeMethodCall(MethodCall(method, arguments)));
if (result == null) {
return null;
}
return codec.decodeEnvelope(result) as T?;
}
}
消息传递过程:
// packages/flutter/lib/src/services/binding.dart
Future<ByteData?> send(String channel, ByteData? message) {
final Completer<ByteData?> completer = Completer<ByteData?>();
ui.PlatformDispatcher.instance.sendPlatformMessage(
channel,
message,
(ByteData? reply) {
try {
completer.complete(reply);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('during a platform message response callback'),
));
}
},
);
return completer.future;
}
平台插件注册与使用:
// 在Dart中使用平台插件
import 'package:camera/camera.dart';
void main() async {
// 确保Flutter初始化完成
WidgetsFlutterBinding.ensureInitialized();
// 获取可用相机列表
final cameras = await availableCameras();
// 使用第一个相机
final camera = cameras.first;
runApp(MyApp(camera: camera));
}
在平台端,插件需要实现对应的原生代码:
// Android端插件实现
public class CameraPlugin implements MethodCallHandler {
private final Activity activity;
CameraPlugin(Activity activity) {
this.activity = activity;
}
// 插件注册方法
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/camera");
channel.setMethodCallHandler(new CameraPlugin(registrar.activity()));
}
// 处理方法调用
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("availableCameras")) {
try {
result.success(getAvailableCameras());
} catch (Exception e) {
result.error("cameraError", e.getMessage(), null);
}
} else {
result.notImplemented();
}
}
}
平台通道的底层实现:
Flutter引擎中,平台通道是通过PlatformMessageChannel
实现的:
// engine/src/flutter/shell/common/shell.cc
void Shell::OnPlatformViewDispatchPlatformMessage(
std::unique_ptr<PlatformMessage> message) {
FML_DCHECK(is_setup_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
if (message->response()) {
// 如果有回调,先记录
fml::RefPtr<PlatformMessageResponse> response = message->response();
// 将平台消息转发给引擎
task_runners_.GetUITaskRunner()->PostTask(
[engine = engine_->GetWeakPtr(), message = std::move(message)]() {
if (engine) {
engine->DispatchPlatformMessage(std::move(message));
}
});
} else {
// 没有回调,直接转发
task_runners_.GetUITaskRunner()->PostTask(
[engine = engine_->GetWeakPtr(), message = std::move(message)]() {
if (engine) {
engine->DispatchPlatformMessage(std::move(message));
}
});
}
}
插件的注册机制:
Flutter在应用启动时会自动注册插件:
// packages/flutter/lib/src/widgets/binding.dart
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding,
GestureBinding, RendererBinding, SemanticsBinding {
void initInstances() {
super.initInstances();
_instance = this;
// 确保Flutter插件已注册
_registerPluginCallbacks();
}
void _registerPluginCallbacks() {
// 在平台上查找已注册的插件
ui.PlatformDispatcher.instance.sendPlatformMessage(
'flutter/plugin_registry',
null,
(ByteData? data) {
// 处理插件注册结果
},
);
}
}
事件通道的实现:
// packages/flutter/lib/src/services/platform_channel.dart
class EventChannel {
const EventChannel(this.name, [this.codec = const StandardMethodCodec()]);
final String name;
final MethodCodec codec;
Stream<dynamic> receiveBroadcastStream([dynamic arguments]) {
final MethodChannel methodChannel = MethodChannel(name, codec);
late StreamController<dynamic> controller;
controller = StreamController<dynamic>.broadcast(onListen: () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMessageHandler(
name,
(ByteData? reply) async {
if (reply == null) {
controller.close();
} else {
try {
controller.add(codec.decodeEnvelope(reply));
} catch (e) {
controller.addError(e);
}
}
return null;
}
);
try {
await methodChannel.invokeMethod<void>('listen', arguments);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('while activating platform stream on channel $name'),
));
}
}, onCancel: () async {
ServicesBinding.instance!.defaultBinaryMessenger.setMessageHandler(name, null);
try {
await methodChannel.invokeMethod<void>('cancel', arguments);
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'services library',
context: ErrorDescription('while de-activating platform stream on channel $name'),
));
}
});
return controller.stream;
}
}
通过平台通道和插件系统,Flutter实现了与原生平台的无缝集成,使开发者能够充分利用平台特定功能。
8.3 首帧渲染全链路分析
Flutter应用的首帧渲染是一个复杂的过程,涉及多个子系统的协同工作。下面是Flutter应用从启动到首帧渲染的完整调用链路分析。
Flutter应用启动和首帧渲染调用链路图:
runApp(MyApp())
│
├── WidgetsFlutterBinding.ensureInitialized() # 确保绑定初始化
│ ├── BindingBase() # 基础绑定
│ ├── ServicesBinding() # 服务绑定
│ ├── SchedulerBinding() # 调度绑定
│ ├── GestureBinding() # 手势绑定
│ ├── RendererBinding() # 渲染绑定
│ └── WidgetsBinding() # Widget绑定
│
├── WidgetsBinding.scheduleAttachRootWidget() # 调度附加根Widget
│ └── Timer.run(() => attachRootWidget()) # 下一帧开始前执行
│
├── WidgetsBinding.attachRootWidget() # 附加根Widget
│ └── RenderObjectToWidgetAdapter.attachToRenderTree() # 创建Element树
│ ├── createElement() # 创建RenderObjectToWidgetElement
│ └── mount() # 挂载Element
│ ├── assignOwner() # 分配BuildOwner
│ ├── _rebuild() # 重建Element
│ │ └── performRebuild() # 执行重建
│ │ ├── child = updateChild() # 更新子Element
│ │ └── widget.createRenderObject() # 创建RenderObject
│ └── attachRenderObject() # 附加RenderObject到父级
│
├── WidgetsBinding.scheduleWarmUpFrame() # 调度预热帧
│ └── Timer.run(() => { # 下一帧开始前执行
│ ├── handleBeginFrame() # 处理帧开始
│ │ ├── SchedulerBinding.handleBeginFrame() # 调度绑定处理帧开始
│ │ └── SchedulerPhase.idle -> persistent -> postFrameCallbacks # 执行各阶段回调
│ │
│ └── handleDrawFrame() # 处理帧绘制
│ ├── WidgetsBinding.drawFrame() # Widget绑定绘制帧
│ │ ├── buildOwner.buildScope() # 构建Widget树
│ │ │ └── Element.rebuild() # 重建Element
│ │ │ └── Element.performRebuild() # 执行重建
│ │ │ └── build() # 构建Widget
│ │ └── buildOwner.finalizeTree() # 完成树构建
│ │
│ ├── RendererBinding.drawFrame() # 渲染绑定绘制帧
│ │ ├── pipelineOwner.flushLayout() # 刷新布局
│ │ │ └── RenderObject.performLayout() # 执行布局
│ │ │ └── RenderObject.layout() # 布局子元素
│ │ │
│ │ ├── pipelineOwner.flushCompositingBits() # 刷新合成位
│ │ │ └── RenderObject._updateCompositingBits() # 更新合成位
│ │ │
│ │ ├── pipelineOwner.flushPaint() # 刷新绘制
│ │ │ └── RenderObject.paint() # 执行绘制
│ │ │ └── RenderObject._paintWithContext() # 使用上下文绘制
│ │ │ └── PaintingContext.canvas.drawXXX() # 绘制到画布
│ │ │
│ │ └── renderView.compositeFrame() # 合成帧
│ │ ├── ui.SceneBuilder() # 创建场景构建器
│ │ ├── layer.buildScene() # 构建场景
│ │ │ └── Layer.addToScene() # 添加图层到场景
│ │ │ └── ui.SceneBuilder.addXXX() # 添加图层操作
│ │ └── ui.Window.render() # 渲染场景
│ │ └── [C++] Dart_InvokeVMServiceMethod("Render") # 调用VM服务
│ │ └── [C++] RuntimeController::Render() # 运行时控制器渲染
│ │ └── [C++] Shell::OnAnimatorDraw() # Shell绘制
│ │ └── [C++] Rasterizer::DrawToSurface() # 光栅器绘制
│ │ ├── [C++] LayerTree::Preroll() # 图层树预处理
│ │ ├── [C++] LayerTree::Paint() # 图层树绘制
│ │ └── [C++] 提交到GPU # 提交到GPU
│ │
│ └── _firstFrameCompleted = true # 标记首帧完成
│
└── Flutter应用显示在屏幕上 # 首帧渲染完成
首帧渲染过程的源码分析:
1. 启动入口 - runApp():
// packages/flutter/lib/src/widgets/binding.dart
void runApp(Widget app) {
// 确保Flutter绑定初始化
WidgetsFlutterBinding.ensureInitialized()
// 调度附加根Widget
..scheduleAttachRootWidget(app)
// 调度预热帧
..scheduleWarmUpFrame();
}
2. 绑定初始化 - WidgetsFlutterBinding.ensureInitialized():
// packages/flutter/lib/src/widgets/binding.dart
static WidgetsBinding ensureInitialized() {
if (_instance == null)
WidgetsFlutterBinding();
return _instance!;
}
// WidgetsFlutterBinding混合了多个绑定
class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
// 构造函数会调用所有mixin的initInstances方法
WidgetsFlutterBinding() {
initInstances();
}
}
3. 附加根Widget - scheduleAttachRootWidget():
// packages/flutter/lib/src/widgets/binding.dart
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
void attachRootWidget(Widget rootWidget) {
// 创建RenderObjectToWidgetAdapter,它是RootWidget和RenderView之间的桥梁
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner, renderViewElement);
}
4. 调度预热帧 - scheduleWarmUpFrame():
// packages/flutter/lib/src/scheduler/binding.dart
void scheduleWarmUpFrame() {
if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle)
return;
_warmUpFrame = true;
final bool hadScheduledFrame = _hasScheduledFrame;
// 一些模拟器不会自动发送初始VSync信号
// 所以我们手动请求一帧
Timer.run(() {
handleBeginFrame(null);
handleDrawFrame();
resetEpoch();
_warmUpFrame = false;
if (hadScheduledFrame)
scheduleFrame();
});
}
5. 处理帧 - handleBeginFrame() 和 handleDrawFrame():
// packages/flutter/lib/src/scheduler/binding.dart
void handleBeginFrame(Duration? rawTimeStamp) {
Timeline.startSync('Frame', arguments: timelineWhitelistArguments);
_firstRawTimeStampInEpoch ??= rawTimeStamp;
_currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
// 如果有动画和帧回调,执行它们
if (schedulerPhase == SchedulerPhase.idle) {
_schedulerPhase = SchedulerPhase.transientCallbacks;
try {
_invokeTransientFrameCallbacks(_currentFrameTimeStamp!);
} finally {
_schedulerPhase = SchedulerPhase.midFrameMicrotasks;
}
}
}
void handleDrawFrame() {
assert(_schedulerPhase == SchedulerPhase.midFrameMicrotasks);
Timeline.finishSync(); // 结束"Frame"部分
try {
// 持久帧回调阶段
_schedulerPhase = SchedulerPhase.persistentCallbacks;
_invokeFrameCallbacks(_FrameCallbackPhase.persistentCallbacks, _currentFrameTimeStamp!);
// 帧后回调阶段
_schedulerPhase = SchedulerPhase.postFrameCallbacks;
_invokeFrameCallbacks(_FrameCallbackPhase.postFrameCallbacks, _currentFrameTimeStamp!);
} finally {
_schedulerPhase = SchedulerPhase.idle;
}
}
6. Widget绑定绘制帧 - WidgetsBinding.drawFrame():
// packages/flutter/lib/src/widgets/binding.dart
void drawFrame() {
try {
if (renderViewElement != null)
buildOwner!.buildScope(renderViewElement!);
super.drawFrame();
buildOwner!.finalizeTree();
} finally {
// ...
}
}
7. 渲染绑定绘制帧 - RendererBinding.drawFrame():
// packages/flutter/lib/src/rendering/binding.dart
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
renderView.compositeFrame(); // 合成帧
pipelineOwner.flushSemantics(); // 确保语义可用
}
8. 合成帧 - RenderView.compositeFrame():
// packages/flutter/lib/src/rendering/view.dart
void compositeFrame() {
if (!kReleaseMode) {
Timeline.startSync('Compositing', arguments: timelineWhitelistArguments);
}
try {
// 创建场景构建器
final ui.SceneBuilder builder = ui.SceneBuilder();
// 构建场景
final ui.Scene scene = layer!.buildScene(builder);
// 渲染场景
window.render(scene);
// 释放场景资源
scene.dispose();
} finally {
if (!kReleaseMode) {
Timeline.finishSync();
}
}
}
9. Flutter引擎渲染 - C++部分:
在Dart调用window.render(scene)
后,控制权传递给C++层:
// engine/src/flutter/lib/ui/window/window.cc
void Window::Render(Dart_NativeArguments args) {
// 获取Scene参数
Scene* scene = tonic::DartConverter<Scene*>::FromArguments(args, 0);
// 获取当前的Shell
UIDartState* dart_state = UIDartState::Current();
std::shared_ptr<tonic::DartState> dart_state_ptr = dart_state->GetWeakPtr();
// 在平台线程上执行渲染
fml::TaskRunner::RunNowOrPostTask(
dart_state->GetTaskRunners().GetPlatformTaskRunner(),
[engine = dart_state->GetEngine(), scene_ptr = scene->scene(),
dart_state_ptr]() {
if (!dart_state_ptr)
return;
// 引擎渲染场景
engine->GetShell().GetPlatformView()->RenderScene(scene_ptr);
});
}
10. Shell和Rasterizer渲染 - C++部分:
// engine/src/flutter/shell/common/rasterizer.cc
void Rasterizer::DrawToSurface(FramePipeline::FrameResult& frame) {
// 获取Surface
auto surface = surface_producer_->ProduceSurface(frame.GetFrameSize());
if (!surface) {
return;
}
// 获取Canvas和GrContext
auto canvas = surface->getCanvas();
auto gr_context = surface_producer_->GetContext();
// 创建合成上下文
CompositorContext::ScopedFrame compositor_frame =
compositor_context_.AcquireFrame(gr_context, canvas, nullptr,
surface_producer_->GetRootTransformation());
// 预处理图层树
frame.GetLayerTree().Preroll(compositor_frame);
// 绘制图层树
frame.GetLayerTree().Paint(compositor_frame);
// 提交Surface
surface_producer_->PresentSurface(std::move(surface));
}
首帧渲染流程总结:
-
初始化阶段:
- 创建并初始化各种绑定(Binding)
- 注册服务和回调
-
构建阶段:
- 创建Widget树
- 创建/更新Element树
- 创建/更新RenderObject树
-
布局阶段:
- 从上到下传递约束
- 从下到上计算尺寸
-
绘制阶段:
- 创建图层树
- 记录绘制命令
-
合成阶段:
- 将图层树转换为场景
- 提交场景到Flutter引擎
-
光栅化阶段:
- 预处理图层树
- 光栅化绘制命令
- 生成纹理
-
渲染阶段:
- 提交到GPU
- 显示到屏幕
首帧渲染完成后,Flutter应用进入正常的渲染循环,通过VSync信号驱动后续帧的渲染。
9. 性能优化原理
Flutter框架设计了多种性能优化机制,确保应用流畅运行。本节深入分析Flutter的性能优化原理。
9.1 重建优化策略
Flutter的UI更新采用增量重建策略,只更新需要变化的部分,从而提高性能。
Element重建优化:
Element树的重建是Flutter性能优化的关键环节:
// packages/flutter/lib/src/widgets/framework.dart
void buildScope(Element context, [VoidCallback? callback]) {
if (callback != null) {
Timeline.startSync('Build', arguments: timelineWhitelistArguments);
try {
callback();
} finally {
Timeline.finishSync();
}
}
// 排序脏元素(按深度升序)
_dirtyElements.sort(Element._sort);
// 仅重建脏元素
int dirtyCount = _dirtyElements.length;
int index = 0;
while (index < dirtyCount) {
final Element element = _dirtyElements[index];
if (element._dirty && element.active) {
element.rebuild();
}
index += 1;
}
// 清空脏元素列表
_dirtyElements.clear();
}
shouldRepaint机制:
CustomPainter使用shouldRepaint减少不必要的重绘:
// packages/flutter/lib/src/rendering/custom_paint.dart
void paint(PaintingContext context, Offset offset) {
// 只有当前绘制器与上一个不同,且shouldRepaint返回true时才重绘
_didChangeSignature = !identical(_painter, _previousPainter) && (_previousPainter == null || _painter == null || _painter!.shouldRepaint(_previousPainter!));
if (_didChangeSignature)
context.canvas.save();
if (_didChangeSignature && erasePaint != null)
context.canvas.drawPaint(erasePaint!);
if (_painter != null)
_painter!._paint(context.canvas, size);
if (_didChangeSignature)
context.canvas.restore();
}
const构造函数优化:
使用const构造函数创建的Widget可以在编译时确定身份,避免不必要的重建:
// 示例: const构造函数优化
class MyWidget extends StatelessWidget {
// 使用const构造函数
const MyWidget({Key? key, required this.title}) : super(key: key);
final String title;
Widget build(BuildContext context) {
// 子Widget使用const构造,当MyWidget重建时,
// 这些子Widget不会创建新实例
return Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFFEEEEEE),
child: const Icon(Icons.star),
);
}
}
StatefulWidget优化:
StatefulWidget的shouldUpdate可以控制是否需要更新:
// packages/flutter/lib/src/widgets/framework.dart
void update(StatefulWidget newWidget) {
final StatefulWidget oldWidget = widget as StatefulWidget;
super.update(newWidget);
final State state = this.state;
// 更新state的widget引用
state._widget = newWidget;
// 只有当shouldUpdateWidget返回true时才调用didUpdateWidget
if (oldWidget != newWidget && state.shouldUpdateWidget(oldWidget)) {
state.didUpdateWidget(oldWidget);
}
state.reassemble();
}
9.2 渲染优化技术
Flutter的渲染系统包含多种优化技术,提高渲染性能。
RepaintBoundary隔离重绘区域:
RepaintBoundary创建独立的图层,防止重绘扩散:
// packages/flutter/lib/src/widgets/basic.dart
class RepaintBoundary extends SingleChildRenderObjectWidget {
const RepaintBoundary({Key? key, Widget? child}) : super(key: key, child: child);
RenderRepaintBoundary createRenderObject(BuildContext context) => RenderRepaintBoundary();
}
// packages/flutter/lib/src/rendering/proxy_box.dart
class RenderRepaintBoundary extends RenderProxyBox {
bool get isRepaintBoundary => true;
void paint(PaintingContext context, Offset offset) {
// 创建新的离屏图层
context.pushLayer(OffsetLayer(), super.paint, offset);
}
}
渲染缓存机制:
Flutter引擎中的RasterCache缓存已绘制的图层:
// engine/src/flutter/flow/raster_cache.cc
sk_sp<SkImage> RasterCache::GetPrerolledImage(
GrDirectContext* context,
SkPicture* picture,
const SkMatrix& ctm,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change) {
// 检查是否应该缓存
if (!ShouldBeCached(picture->uniqueID(), is_complex, will_change)) {
return nullptr;
}
// 查找缓存
auto it = cache_.find(picture->uniqueID());
if (it == cache_.end()) {
return nullptr;
}
Entry& entry = it->second;
if (entry.access_count < access_threshold_) {
// 增加访问计数
entry.access_count++;
return nullptr;
}
// 检查是否需要重新渲染
if (entry.image == nullptr) {
entry.image = RasterizePicture(context, picture, ctm, dst_color_space);
}
return entry.image;
}
分层渲染:
Flutter使用分层渲染系统,只更新变化的图层:
// packages/flutter/lib/src/rendering/layer.dart
class ContainerLayer extends Layer {
void addToScene(ui.SceneBuilder builder, [Offset layerOffset = Offset.zero]) {
addChildrenToScene(builder, layerOffset);
}
void addChildrenToScene(ui.SceneBuilder builder, [Offset childOffset = Offset.zero]) {
// 只添加需要更新的子层
for (Layer child in _children!) {
if (child._needsAddToScene) {
child.addToScene(builder, childOffset);
}
}
}
}
Skia快速路径:
Flutter利用Skia的快速路径优化常见绘制操作:
// engine/src/third_party/skia/src/core/SkCanvas.cpp
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
// 检查是否可以使用快速路径
if (paint.canComputeFastBounds()) {
SkRect storage;
if (this->quickReject(paint.computeFastBounds(r, &storage))) {
return;
}
}
// 使用快速路径绘制矩形
this->onDrawRect(r, paint);
}
9.3 内存管理与优化
Flutter的内存管理包括Dart垃圾回收和原生资源管理。
Dart内存管理:
Flutter使用Dart VM的垃圾回收机制管理内存:
// Dart内存管理示例
void memoryManagementExample() {
// 创建局部变量
var list = List.generate(10000, (i) => i);
// 离开作用域后,list会被垃圾回收
print('List created');
// 主动触发垃圾回收(仅用于演示,实际应用中不应该这样做)
// ignore: invalid_use_of_visible_for_testing_member
// ignore: invalid_use_of_protected_member
// HeapProfiling.collectAllGarbage();
}
图像缓存管理:
Flutter的ImageCache控制图像内存使用:
// packages/flutter/lib/src/painting/image_cache.dart
class ImageCache {
// 默认最大图像数量
static const int _kDefaultSize = 1000;
// 默认最大内存使用量(字节)
static const int _kDefaultSizeBytes = 100 << 20; // 100 MiB
// 当前缓存的图像数量
int get currentSize => _cache.length;
// 当前内存使用量
int get currentSizeBytes => _currentSizeBytes;
// 清除缓存
void clear() {
_cache.clear();
_liveImages.clear();
_pendingImages.clear();
_currentSizeBytes = 0;
}
// 缓存图像
void putIfAbsent(Object key, ImageStreamCompleter Function() loader) {
// 检查是否已在缓存中
final _CachedImage? image = _cache.remove(key);
if (image != null) {
_cache[key] = image;
return image.completer;
}
// 检查是否有足够空间
final int imageSize = _pendingImages[key]?.second ?? 0;
if (maximumSize > 0 && _cache.length + 1 > maximumSize) {
_checkCacheSize(imageSize);
}
// 加载并缓存图像
final ImageStreamCompleter completer = loader();
_pendingImages[key] = Pair<ImageStreamCompleter, int>(completer, imageSize);
return completer;
}
}
资源释放机制:
Flutter确保资源在不再需要时释放:
// packages/flutter/lib/src/widgets/image.dart
void dispose() {
_imageStream?.removeListener(ImageStreamListener(_handleImageFrame));
_imageStream = null;
super.dispose();
}
内存泄漏防护:
Flutter提供了工具帮助检测和防止内存泄漏:
// packages/flutter/lib/src/widgets/binding.dart
void addObserver(WidgetsBindingObserver observer) {
_observers.add(observer);
}
void removeObserver(WidgetsBindingObserver observer) {
_observers.remove(observer);
}
正确实现dispose方法防止内存泄漏:
class MyWidget extends StatefulWidget {
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
// 可能占用资源的控制器
late AnimationController _controller;
late StreamSubscription _subscription;
void initState() {
super.initState();
_controller = AnimationController(vsync: this);
_subscription = someStream.listen((_) {});
}
void dispose() {
// 释放资源
_controller.dispose();
_subscription.cancel();
super.dispose();
}
Widget build(BuildContext context) {
return Container();
}
}
通过这些优化技术,Flutter可以在各种设备上提供流畅的用户体验。理解这些优化原理有助于开发者创建高性能的Flutter应用。

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)