Flutter Widget 体系完全讲解:Widget、Element、RenderObject 到自定义控件全梳理
Flutter UI的核心是Widget→Element→RenderObject三层协作机制。Widget是轻量级的UI描述,Element管理生命周期和状态复用,RenderObject负责实际的布局和绘制。理解这一架构能解答性能优化、局部刷新等关键问题。开发者通常只需编写Widget,但自定义控件可分为四个层级:组合式Widget、StatefulWidget、CustomPainter和最
一句话总结:
Flutter UI 的本质不是 Widget,而是 Widget → Element → RenderObject 三层协作。
Widget 只是描述,RenderObject 才是真正画出界面的对象,而 Element 是两者之间的管理者。
本文从底层原理讲到自定义控件,帮助你构建完整、准确、可复用的 Flutter UI 心智模型。
1. 为什么要理解 Widget / Element / RenderObject?
大部分人知道 Flutter 是“声明式 UI”,但长期只写 Widget 很容易产生误解:
- 为什么 Widget 每帧都能重建但不卡?
- 为什么 setState 后界面能局部刷新?
- 为什么自定义控件有时要写 RenderObject?
理解三层结构后,这些问题全部迎刃而解。
2. Flutter UI 的三层结构(核心结论)
Widget(描述)
↓ build()
Element(生命周期管理)
↓ createRenderObject()
RenderObject(布局 + 绘制)
三者分工非常明确:
| 层级 | 作用 | 类比(Android) |
|---|---|---|
| Widget | UI 的声明,immutable | XML、View 的属性 |
| Element | 真实 UI 树、生命周期、复用渲染对象 | ViewHolder / 中间管理层 |
| RenderObject | 负责布局 & 绘制,是最底层核心 | View / ViewGroup(onMeasure/onLayout/onDraw) |
3. Widget:声明 UI(轻量、不可变)
这是我们平常写的部分,例如:
Text("Hello")
Container(...)
Row(...)
Widget 特点:
-
不可变(immutable)
-
build() 非常轻量,可以随意重建
-
不包含尺寸信息、不绘制、不管理状态
-
只是描述 UI(说明书)
Flutter 性能高的核心之一就是:
Widget 可以频繁重建,因为它们非常轻量。
4. Element:真正的 UI 树(你看不到,但非常重要)
Element 是 Widget 的“实例”,在运行时持久存在。
Element 的三个关键职责:
✔ 1. 构建并维护 Element Tree(真实 UI 树)
Widget Tree 会不断重建,但 Element Tree 才是真正在内存中维持的 UI 树。
✔ 2. 保存 StatefulWidget 的 State
State 挂载在 StatefulElement 上,而不是 Widget 本身。
✔ 3. 复用 RenderObject(性能关键)
当 Widget 更新时:
- Widget 新实例 ≠ 重新创建渲染对象
- Element 会复用原有 RenderObject,只更新属性
这就是为什么:
setState 不会让整个树重建,只会局部重建。
5. RenderObject:真正画 UI 的层(布局 + 绘制)
RenderObject 是最核心的底层渲染单位。
它负责两件事:
✔ Layout:计算大小 & 子节点位置
对应 Android 的:
- onMeasure
- onLayout
例如:
- RenderFlex(Row/Column 的布局)
- RenderStack(堆叠布局)
- RenderParagraph(Text 布局)
✔ Paint:绘制
对应 Android 的:
-
onDraw(Canvas)
例如:
- 绘制文本(RenderParagraph)
- 绘制图片(RenderImage)
- 绘制背景(RenderDecoratedBox)
一句话:
你在屏幕上看到的像素,都是 RenderObject 画出来的。
6. 开发者平常为什么接触不到 Element 和 RenderObject?
因为 Flutter 做到了最佳封装:
- 你写 Widget(声明 UI)
- Element 自动帮你管理生命周期/状态/复用渲染对象
- RenderObject 自动进行布局和绘制
绝大多数场景,你完全不需要关心 Element 和 RenderObject。
写 Widget 就够了。
7. 自定义 Widget 分四层(非常重要)
第一层:组合型自定义 Widget(最常用,几乎全靠它)
你写:
class MyCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(color: Colors.white),
child: Column(
children: [
Text("Title"),
SizedBox(height: 10),
Text("Content"),
],
),
);
}
}
你只是把:
-
Container
-
Text
-
Column
组合成一个新的“小组件”。
🔸 这是最常见的自定义 Widget
🔸 根本不会接触 Element、RenderObject
🔸 Flutter 会自动帮你创建 Element/RenderObject
你只需要写 build()。
第二层:带 State 的自定义 Widget(StatefulWidget)
比如计数器:
class Counter extends StatefulWidget {
@override
_CounterState createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int count = 0;
@override
Widget build(BuildContext context) {
return Text("$count");
}
}
你还是在写 Widget,不接触 Element/RenderObject。
虽然底层是:
- StatefulElement
- State 存在 Element 中
但你不需要操作它们。
第三层:CustomPaint(轻绘制),但不自定义布局
如果你想画图:
CustomPaint(
painter: MyPainter(),
);
写一个 painter:
class MyPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
canvas.drawCircle(...);
}
}
👉 这里开始接触到绘制了,但不是 RenderObject。
👉 painter = “轻量绘制层”,它帮你画图,但不能改变布局。
你仍然没进入 RenderObject 的世界。
第四层(高级):自定义 RenderObject(真正底层)
只有下面情况才需要:
- 自己实现布局算法(比如瀑布流)
- 自己实现性能更高的控件
- 需要读/写 RenderObject 属性
- 需要完全控制 Layout + Paint
你才会写:
class MyBox extends LeafRenderObjectWidget {
@override
RenderObject createRenderObject(BuildContext context) {
return MyRenderBox();
}
}
class MyRenderBox extends RenderBox {
@override
void performLayout() {
size = constraints.constrain(Size(100, 50));
}
@override
void paint(PaintingContext ctx, Offset offset) {
ctx.canvas.drawRect(offset & size, Paint()..color = Colors.red);
}
}
👉 这个才叫真正“自定义 RenderObject Widget”
👉 一般业务场景 99% 用不到
👉 这种属于 SDK 级别、轮子级别
对应 Android 的:
自定义 View(onMeasure / onLayout / onDraw)
例如:
- 自定义 Flow Layout
- 自定义瀑布流
- 可拖拽控件
- 高性能图形控件
- 完全自定义 UI 组件
8. RenderObject vs Android 自定义 View(非常关键的对应)
| Android | Flutter | 相同点 |
|---|---|---|
| View | RenderObject | 渲染核心 |
| onMeasure | performLayout | 测量 |
| onLayout | performLayout 内为子布局 | 布局 |
| onDraw(Canvas) | paint(Canvas) | 绘制 |
| invalidate() | markNeedsLayout/paint | 标脏重绘 |
| ViewGroup | MultiChildRenderObject | 多子布局 |
可以说:
Flutter 自定义 RenderObject = Android 自定义 View(本质一致)
9. 整体体系图(建议你用于 PPT)
Widget Tree(声明)
↓
Element Tree(生命周期、复用)
↓
Render Tree(布局 + 绘制)
↓
显示到屏幕
再配一句:
你写的是 Widget,真正画的是 RenderObject。
中间由 Element 负责连接和复用。
扩展
近年来,前端框架(React、Vue)与跨平台 UI 框架(Flutter)虽然看似来自不同世界,但它们在核心思想上却惊人地一致:
都采用了声明式 UI、虚拟节点、框架调度、局部更新、自动渲染管线等理念。
很多学习 Flutter 的开发者在深入理解 Widget、Element、RenderObject 三层后都会产生一个直觉:
这不就是 Flutter 版本的 React/Vue 吗?
Flutter 甚至把 Virtual DOM 替换成自己的 Widget/Element/RenderObject!
结论:
Flutter 的三层体系和 React / Vue 的思想高度一致
下一篇:
更多推荐

所有评论(0)