Flutter框架设计思想
比如你需要一个根据子节点特定属性来排列的复杂容器。
Flutter是Google推出的跨平台 UI 框架,用一套Dart代码就能同时开发高性能、高保真的 Android、iOS、Web、桌面等多端原生应用。

Flutter的设计思路
🚀一次编写,到处运行✨
可一个流程概括为:Widget → Element → RenderObject → Layer → Skia → GPU
Framework层【Widget | Element | RenderObject】: 这是开发者最常接触的部分。它包含了Material(安卓风格)和 Cupertino(iOS 风格)组件库。
---------------------------------------------------------------------------------------------------------------------
Engine层【Layer | Skia】: 这是 Flutter 的心脏,主要由C++/Rust编写。它包含了图形渲染(基于 Impeller/Skia)、文字布局和 Dart 运行时。这意味着 Flutter 不依赖系统原生控件,而是自己在画布上“画”出 UI,从而保证了双端体验的高度一致。
---------------------------------------------------------------------------------------------------------------------
Embedder层【GPU】: 负责让Flutter运行在具体的平台上(如 Android、iOS、Web、Windows),处理与系统的交互。
注: Flutter 3.10开始,iOS端已默认使用Impeller引擎替代Skia,以解决着色器编译卡顿(Jank)问题,Android也在逐步适配中。
Flutter链条流程介绍
| 阶段 | 对象 | 职责 |
| 框架层 (Framework) | Widget | 我想要什么(配置) |
| Element | 我该怎么做(逻辑/组件状态) | |
| RenderObject | 我在哪里,长多大(布局/绘制) | |
| 引擎层 (Engine) | Layer | 如何分层叠加(合成) |
| Skia / Impeller | 如何变成像素指令(光栅化) | |
| 硬件层 (Hardware) | GPU | 最终显示(图形计算) |
📦 Widget
它是不可变的(Immutable),描述了UI的配置信息。你只是在告诉 Flutter:“我想要.....”。
在开发中,Widget用的比较多有StatelessWidget和StatefulWidget。
| 维度 | StatelessWidget | StatefulWidget |
| Element 类型 | StatelessElement |
StatefulElement |
| 生命周期 | 只有 build |
拥有 initState, didUpdateWidget, dispose 等丰富周期 |
| 内存占用 | 极低(随用随走) | 略高(需要维护 State 对象的内存) |
| 重绘触发 | 依赖父组件传入的新配置 | 既依赖父组件,也可以通过 setState 自我触发 |
StatelessWidget
💫没有可变化的状态,所有数据都是“静态”的。它就像一张打印出来的传单,一旦印好,内容就固定了。
StatefulWidget
💫内部有可变化的状态,状态变了UI会自动重新构建。它由两个类组成:Widget类本身和对应的State类。
StatefulWidget生命周期:
| 方法 | 调用频率 | 典型用途 |
initState |
仅 1 次 | 初始化变量、网络请求、监听器。 |
didChangeDependencies |
多次 | 获取 Context 相关的依赖(如主题颜色)。 |
didUpdateWidget |
多次 | 响应父组件传入参数的变化。 |
build |
极多次 | 描述 UI 结构,保持纯净。 |
setState |
开发者触发 | 标记 UI 为“脏”,触发重绘。 |
dispose |
仅 1 次 | 销毁资源、断开监听,防止内存泄漏。 |
🧩 Element
它是 Widget 和 RenderObject 之间的桥梁。Element 负责管理状态和生命周期,它决定了当 Widget 改变时,是更新现有的 RenderObject 还是重新创建一个。注意 Element 并不存储Widget 的 "UI样式"!

我们常见的 BuildContext 其实就是 Element 的‘对外名片’。当Widget被加载到Widget树时,就自动为其分配一个Element。Widget 通过这张名片,在茫茫的组件树中认清自己的坐标,并以此为媒介去索取状态或其他节点的资源。
abstract class Element extends DiagnosticableTree implements BuildContext {
// ... 各种内部实现
}
🎨 RenderObject
它是 Flutter 渲染引擎的核心,也是顶级牛马🐮🐴。它主要负责处理最底层的布局(Layout)和绘制(Painting)。
布局(Layout):
-
父节点传递约束:父节点告诉子节点:“你最小不能小于这个尺寸,最大不能超过那个尺寸。”
-
子节点决定尺寸:子节点根据约束计算自己的大小,并告诉父节点:“好的,我决定占用这么大的空间。”
绘制(Painting):
当布局完成后,RenderObject 会通过 paint 方法将自己画出来。它使用的是底层的 Canvas API,这和原生的 Android 或 iOS 开发非常相似。
在开发中,我们很少用到RenderObject,以下是RenderObject的应用场景:
-
极高性能需求:需要精细控制绘制过程,减少重绘开销。
-
特殊视觉效果:现有的 Widget(如
Stack,CustomPaint)无法实现的复杂布局。 -
自定义布局逻辑:比如你需要一个根据子节点特定属性来排列的复杂容器。
🥞 Layer
在 RenderObject 完成布局和绘制后,所有的绘制指令并不是直接“死板”地画在屏幕上的,而是分布在不同的 Layer 上。
如果整个 App 只有一张画布,哪怕只有一小块区域(比如一个加载动画)在动,Flutter 也必须重新绘制整个屏幕,这太浪费性能了。
Layer 的存在是为了“合成(Compositing)”:
重绘优化:通过将经常变化的部分(如滚动列表、动画)放在独立的 Layer 中,当它们变化时,只需要重新处理这一层,然后由 GPU 将所有层叠加(合成)在一起即可。
复杂特效:像剪裁(Clip)、透明度(Opacity)、阴影(Shadow)和模糊(Blur)这些效果,通常都是通过操作 Layer 来实现的。
也就是说:Layer 就像是一个分层化的加工车间,每个 Layer 负责执行特定的视觉任务(像PhotoShop的图层),最终由引擎将这些独立的图层合成为一帧完整的画面。

✍️ Skia / Impeller
Skia 是一个高性能的开源 2D 图形库,它通过封装底层的图形 API(如 OpenGL、Metal),将绘图指令转化为屏幕上的像素。它是 Flutter 实现全平台视觉一致性的核心引擎。
虽然 Skia 功能强大,但其在运行时动态编译着色器(Shader)的特性,有时会导致著名的**‘着色器编译卡顿’**。为了攻克这一顽疾,Flutter 团队推出了 Impeller——这是一个专为现代 GPU 设计的新引擎,通过在构建期预编译着色器,从架构底层彻底解决了渲染掉帧问题。”
——By Gemini
更多推荐

所有评论(0)