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用的比较多有StatelessWidgetStatefulWidget

维度 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样式"!

Element Tree的每个节点都引用了一个 Widget,并维护着与其他Element节点之间的父子拓扑关系。

我们常见的 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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐