Flutter的三棵树

“三棵树”是 Flutter 渲染和构建UI的核心机制,理解它们对于掌握 Flutter 至关重要。这三棵树分别是:

  1. Widget 树

  2. Element 树

  3. RenderObject 树

它们协同工作,以实现 Flutter 的高性能渲染和高效的响应式编程模型。

Flutter 是声明式的UI,它只需要描述UI是什么样的,而不需要一步步地指挥框架如何去构建和更新这个界面。

为了更好的理解可先了解:命令式 UI 和 声明式 UI

一、Flutter的三棵树

1. Widget 树 (What to render)

  • 是什么:Widget 是你用代码声明的UI配置。它是一个不可变的(immutable)描述,告诉 Flutter 这部分UI应该长什么样子。你可以把它看作是一份蓝图

  • 特点

    • 轻量级:Widget 本身并不负责实际的渲染或状态管理,它只持有最终的配置信息(如颜色、字体、尺寸等)。

    • 不可变:一旦创建就不能修改。当UI需要变化时,你必须创建一个新的 Widget。这种immutability使得Widget的创建和销毁非常快速。

    • 组合性:复杂的UI由无数个简单的小Widget嵌套组合而成(如Column > Row > Container > Text)。

例子:这段代码就定义了一棵小小的 Widget 树。

Container( // Widgetcolor: Colors.blue,child: Center( // Widgetchild: Text('Hello World'), // Widget),
);

2. Element 树 (How to render & Where)

  • 是什么:Element 是 Widget 在UI树中具体位置的实例化体现。它是连接 Widget 和 RenderObject 的粘合剂,负责管理UI的更新和生命周期。

  • 特点

    • 可变且有状态:Element 是长寿命的,在UI重建时会持续存在(只要同一个位置的runtimeTypekey没变)。

    • 职责

      1. 挂载:它持有对对应 Widget 和 RenderObject 的引用。

      2. 比较:当UI重建,新的 Widget 树到来时,Element 会负责将新的 Widget 与它当前持有的旧 Widget 进行对比(Widget.canUpdate)。

      3. 更新:如果新的 Widget 和旧的 Widget 是同一类型(runtimeTypekey相同),Element 会更新自己持有的 Widget 引用,并告诉 RenderObject 是否需要更新(reconfigure)。

      4. 重建:如果对比失败,Element 会销毁旧的并创建新的 Element 和 RenderObject。

简单来说,Element 决定了是复用现有的UI结构,还是销毁重建。

3. RenderObject 树 (Actually rendering)

  • 是什么:RenderObject 是真正负责布局(Layout)和绘制(Paint) 的核心组件。它计算每个UI元素的大小和位置,并将它们绘制到屏幕上。

  • 特点

    • 重量级:布局和绘制的计算成本很高,因此 RenderObject 的创建和更新需要非常谨慎。

    • 核心方法

      • performLayout():计算自身和子节点的大小和位置。

      • paint():将自己绘制到画布(Canvas)上。

    • 持久化:只要有可能,Flutter 会极力避免重新创建和重新布局 RenderObject,以保持渲染性能的流畅。

大多数开发者通常不直接操作 RenderObject,而是通过熟悉的 Widget(如ContainerStackAlign)来间接使用它们。

二、三棵树如何协同工作?

让我们通过一个简单的计数器例子来看整个流程:

初始构建阶段

  1. 你编写了 MyHomePage Widget 树。

  2. Flutter 遍历你的 Widget 树,自上而下地创建对应的 Element

  3. 每个 Element 又会调用 Widget 的 createRenderObject() 方法,创建相应的 RenderObject

  4. 三棵树都构建完毕,RenderObject 树进行布局和绘制,UI显示在屏幕上。

更新阶段

(当你按下按钮,counter增加)

​​​​​​​​​​​​​​
  1. setState(() { _counter++; }) 被调用,标记该 StatefulWidget 的 Element 为“脏”状态。

  2. 下一帧到来时,Flutter 会触发重建对应的 Widget 子树。build 方法被再次调用,返回一棵新的 Text($_counter) Widget。

  3. 关键的对比过程(Diff)

    • 对应的 Element 会拿着这个新的 Text Widget,与它当前持有的旧的 Text Widget 进行比较。

    • 它发现两者的 runtimeType 都是 Text,并且都没有设置 key,所以可以更新。

  4. 高效的更新

    • Element 简单地更新它持有的 Widget 引用为新的 Widget。

    • 然后,Element 会通知它对应的 RenderObject:“配置有变化,你需要更新了”。

    • RenderObject 检查发现只是文本内容变了,它可能会标记自己需要重绘(repaint),但通常不需要重新布局(relayout)(因为文字大小可能没变)。

  5. 下一帧,RenderObject 只进行必要的重绘,新的数字就显示出来了。

三、为什么需要三棵树? (优点)

  1. 性能优化:将轻量级的、不可变的 Widget 与重量级的、可变的 RenderObject 分离。UI的频繁重建(创建新Widget)成本极低,而真正昂贵的布局和绘制过程只有在必要时才进行。

  2. 高效的响应式编程:通过 Element 树的 Diff 算法,Flutter 可以精确地知道UI的哪一部分发生了变化,从而只更新必要的 RenderObject,而不是整个界面。这比传统的命令式UI(如Android/iOS原生)手动操作View要高效得多。

  3. 逻辑与渲染分离:开发者只需关心如何用 Widget 描述UI(声明式),而无需关心具体的渲染细节和更新逻辑,框架帮你处理了所有复杂性。

四、总结

角色特点职责
Widget 树蓝图/配置轻量、不可变描述UI元素应该是什么样子
Element 树粘合剂/管理者可变、长寿命管理Widget的更新,决定是复用还是重建UI
RenderObject 树渲染工人重量级、持久负责实际的布局、绘制工作,计算尺寸和位置,渲染到屏幕

简单记忆Widget 是配置,Element 是管家,RenderObject 是干活的。 管家(Element)根据新的图纸(Widget)来决定是让工人(RenderObject)在原基础上修改,还是直接换一个新工人。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921404.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921404.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

同一台nginx中配置多个前端项目的三种方式

目录 第一种方式:配置多个二级域名 第二种方式:配置端口转发(不推荐) 第三种方式:同一个server中基于location配置(重点讲解) 第一种方式:配置多个二级域名 一个域名下面申请多个二级域名,每个二级域名配置一个vue前端项目,这个很好配置,在这里不再详细说明。 …

第二家公司虽然用PowerBI ,可能更适合用以前的QuickBI

第二家公司虽然用PowerBI ,可能更适合用以前的QuickBI现在回想一下,第二家公司数据源是MySQL ,常规报表是用excel报表,另外还做了一张能发布到web的看板供运营使用。基于基本情况,quickbi 的早期版本是合适的&#xff…

STM32 USBx Device HID standalone 移植示例 LAT1466

关键字:USBx, Device, HID,standalone 1.设计目的 目前 USBx Device standalone 的官方示例较少,不过使用 STM32CubeMX 可以快速地生成 USBx Device 相关类的示例工程,会很方便大家的开发。这里以 NUCLEO-H563 为例&…

python创建并写入excel文件

大家好,这里是七七,今天来跟大家分享一个python创建并写入一个excel文件的小例子,话不多说,开始介绍。首先我们来看一下这一小段代码。import openpyxl# 创建一个新的 Excel 工作簿workbook openpyxl.Workbook()# 获取当前活动的…

react native 出现 FATAL EXCEPTION: OkHttp Dispatcher

react native 出现 FATAL EXCEPTION: OkHttp Dispatcher 报错信息FATAL EXCEPTION: OkHttp DispatcherProcess: , PID: 8868java.lang.NoSuchMethodError: No virtual method toString(Z)Ljava/lang/String; in class Lokhttp3/Cookie; or its super classes (declaration of o…

sentinel实现控制台与nacos数据双向绑定

有两种方式可以实现&#xff1a;Springboot客户端做相应配置&#xff08;推荐&#xff09;修改sentinel-dashboard的源码一、Springboot客户端做相应配置&#xff08;推荐&#xff09;1、添加依赖<dependency><groupId>com.alibaba.csp</groupId><artifac…

Kubernetes (k8s)

Kubernetes (k8s) 以下是一份 ​Kubernetes (k8s) 基础使用教程&#xff0c;涵盖从环境搭建到核心操作的完整流程&#xff0c;附详细命令和示例&#xff1a; &#x1f680; ​一、环境准备&#xff08;3种方式&#xff09;​​ ​1. 本地开发环境&#xff08;推荐&#xff09;​…

三打ANSYS HFSS

2. 激励方式&#xff08;端口&#xff09;详细对比分析在HFSS中&#xff0c;“激励方式”和“端口”这两个词经常混用&#xff0c;但严格来说&#xff0c;“端口”是实现“激励”的一种最主要的方式。端口类型工作原理适用情况优点缺点波端口 (Wave Port)默认首选。计算端口的固…

3.python——数据类型转换

python的数据类型转换分为两种&#xff1a; 隐式转换&#xff1a;自动完成 显式转换&#xff1a;用类型函数转换 隐式转换 # 自动转为浮点数 num_int 123 num_flo 1.23num_new num_int num_flo显式转换 整型 x int(1) # x 输出结果为 1 y int(2.8) # y 输出结果为 2 z …

迅为RK3568开发板OpenHarmonyv3.2-Beta4版本测试-命令终端

将串口连接到开发板的调试串口&#xff0c;进入 OpenHarmony 系统后&#xff0c;会自动进入 OpenHarmony终端&#xff0c;如下图所示&#xff1a;

【面试题】介绍一下BERT和GPT的训练方式区别?

BERT(双向编码器): 预训练任务: 掩码语言模型(MLM):随机掩盖15%的token,其中: 80%替换为[MASK] 10%替换为随机token 10%保持原样 下一句预测(NSP):判断两个句子是否连续(后续版本已移除) 训练特点: 使用双向Transformer编码器 同时利用左右上下文信息 适合理解类任…

邪修实战系列(1)

1、第一阶段邪修实战总览&#xff08;9.1-9.30&#xff09; 把第一阶段&#xff08;基础夯实期&#xff09;的学习计划拆解成极具操作性的每日行动方案。这个计划充分利用我“在职学习”的特殊优势&#xff0c;强调“用输出倒逼输入”&#xff0c;确保每一分钟的学习都直接服务…

XR数字融合工作站打造智能制造专业学习新范式

智能制造是工业4.0的核心发展方向&#xff0c;涵盖数字化设计、智能生产、工业机器人、数字孪生、物联网等关键技术。然而&#xff0c;传统教学模式在设备成本高、实训风险大、抽象概念难理解等方面存在诸多挑战。XR数字融合工作站,利用VR/AR/MR等技术&#xff0c;通过虚拟仿真…

基于FPGA实现数字QAM调制系统

基于FPGA实现数字QAM调制系统题目要求一、代码设计1.顶层2.分频3.m序列4.串转并5.映射6.正弦波余弦波生成ROM和7.ask二、仿真波形总结题目要求 FPGA实现数字QAM调制系统要求根据正交振幅调制原理&#xff0c;利用正弦载波信号发生器&#xff0c;实现调制信号。调制原理会利用到…

DAY 22 复习日

浙大疏锦行复习日 仔细回顾一下之前21天的内容&#xff0c;没跟上进度的同学补一下进度。 作业&#xff1a; 自行学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 导入需要的库 import pandas as pd # 用于数据处理和分析&#xff0c;…

biocmanager安装 库 老是提示网络连接错误 才尝试各种办法

您好&#xff0c;遇到 BioManager &#xff08;通常是 BiocManager&#xff09;安装R包时提示网络连接错误确实非常令人头疼。这通常与R/RStudio的配置、网络环境&#xff08;尤其是国内用户&#xff09;或SSL证书问题有关。 请不要着急&#xff0c;我们可以按照从易到难的顺序…

【开题答辩全过程】以 智能商品数据分析系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

解构复杂财务逆向业务:如何优雅地生成与管理负数单?

文章目录一 核心复杂性二 关键设计模式&#xff1a;三 棘手场景与解决方案&#xff1a;1.分批合并处理&#xff1a;负数单需能智能拆分&#xff0c;精准冲销多批次的正向单据。2.优先级问题&#xff1a;3.超额处理&#xff1a;系统应坚决拦截而非处理&#xff0c;防止资金损失和…

Android集成OpenCV4实例

Android集成OpenCV4分以下几步骤&#xff1a; 使用Android Studio Giraffe | 2022.3.1创建一个Empty Views Activity空项目&#xff0c;包名为&#xff1a;com.example.andopencvdemo00 &#xff0c; 创建成功后&#xff0c;进行以下相关设置&#xff1a; 第一步&#xff1a;在…

npy可视化方法

npviewer 是一个应用程序&#xff0c;它允许您以热图的形式可视化 numpy 的 npy 文件中的数据。该应用程序根据不同的模式自动选择适当的维度进行显示。 根据不同的模式自动选择适当的维度进行显示支持不同格式的 numpy 数据的可视化&#xff0c;如 RGB 和灰度用户友好的界面使…