当前位置: 首页 > news >正文

Flutter源码分析笔记:Widget类源码分析

Flutter源码分析笔记
Widget类源码分析

- 文章信息 - Author: 李俊才 (jcLee95)
Visit me at: https://jclee95.blog.csdn.net
Email: 291148484@163.com.
Shenzhen China
Address of this article:https://blog.csdn.net/qq_28550263/article/details/132259681

【介绍】:本文记录阅读与分析Flutter源码 - Widget类源码分析。


1. 概述

Widget类是Flutter框架中的核心类之一,用于描述用户界面的一部分。它是一个不可变的描述,可以被实例化为元素(Element),后者负责管理底层的渲染树。

Widget是Flutter框架的基础,用于描述用户界面的一部分,不可变且无状态。它有一些用于实例化元素、诊断调试和比较的方法和属性,同时它的子类可以是StatelessWidget或StatefulWidget,用于构建静态或有状态的用户界面部分。

这部分源码见附录F-1。

2. 属性

2.1 key

key属性控制一个widget如何替换树中的另一个widget。如果两个widget的runtimeType和key属性分别通过operator==比较是相等的,那么新的widget将通过更新底层元素来替换旧的widget。否则,旧的元素会从树中移除,新的widget会被实例化为元素,然后插入树中。

3. 方法

3.1 createElement()

该方法将配置实例化为一个具体的元素(Element)。一个widget可以在树中被包含零次或多次,每次被包含在树中时,都会被实例化为一个元素。

3.2 canUpdate(Widget oldWidget, Widget newWidget)

该方法用于判断一个新的widget是否可以用来更新一个已有元素的配置。根据runtimeType和key属性的比较来判断两个widget是否可以更新。

3.3 debugFillProperties(DiagnosticPropertiesBuilder properties)

debugFillProperties(DiagnosticPropertiesBuilder properties):向诊断信息属性构建器添加属性,用于调试和诊断。在子类中可以重写以提供更多的调试信息。

3.4 _debugConcreteSubtype(Widget widget)

返回一个数值,表示特定Widget子类型的具体编码。用于在热重载时判断已挂载元素的配置是否被修改。

3.5 其它

operator ==(Object other) 和 get hashCode

实现运算符”==“用于判断两个widget是否相等,以及计算它们的哈希值。

toStringShort()

返回此widget的简短文本描述,通常是它的runtimeType和key的组合。

4. 继承关系

4.1 Widget的父类

Widget 是一个抽象类,继承自 DiagnosticableTree(这个类表示诊断树,主要用于提供调试信息),因此继承了一些用于调试和诊断的方法和属性。

4.2 Widget的子类

4.2.1 StatefulWidget 和 StatelessWidget

Widget 本身没有可变状态,它的所有字段都必须是 final。如果需要关联可变状态,应该使用 StatefulWidget,后者在被实例化为元素并添加到树中时会创建一个State对象。Widget的子类可以是 StatelessWidget(始终以相同的方式构建)或 StatefulWidget(可以在其生命周期内多次构建)。

在这里插入图片描述
StatefulWidget: 这是一个带有可变状态的 Widget 类别。它由两部分组成:一个是不可变的描述部分(Widget),另一个是可变的状态部分(State)。StatefulWidget 实例在构建过程中可以改变其状态,当状态发生变化时,相关的 State 对象会被重新构建以更新界面。适用于有变化状态的部分,比如用户输入、数据加载等。
StatelessWidget: 这是一个不可变的 Widget 类别,其描述和外观在整个生命周期内保持不变。StatelessWidget 实例在构建时不会持有可变状态,因此适用于不需要变化的 UI 部分,如图标、文本等。

Widget可以被多次包含在树中,每次都会被实例化为元素。如果某个 widget 在树中出现多次,它将被多次实例化。

4.2.2 RenderObjectWidget

RenderObjectWidget是Flutter渲染引擎的一部分,表示屏幕上的可见对象,它又有LeafRenderObjectWidgetSingleChildRenderObjectWidgetMultiChildRenderObjectWidget这三个子类。
在这里插入图片描述

  • LeafRenderObjectWidget: 这是一种将 RenderObject 无需管理子元素的 Widget 类别。它通常用于将自定义的绘制逻辑封装为 Widget,然后通过构建 RenderObject 进行绘制。
  • SingleChildRenderObjectWidget: 这是一种管理单个子元素的 RenderObjectWidget 类别。它会创建一个单一的子元素,并将其作为子节点传递给 RenderObject 进行渲染。
  • MultiChildRenderObjectWidget: 这是一种管理多个子元素的 RenderObjectWidget 类别。它会创建多个子元素,并将它们作为子节点传递给 RenderObject 进行渲染。比如 Stack、Column 和 Row 等都是 MultiChildRenderObjectWidget 的子类。

4.2.3 ProxyWidget

ProxyWidget提供一种方式来包装 Widgets,以实现特定的功能。它是一个具有子WidgetWidget,而非新的Widget

在这里插入图片描述

  • ParentDataWidget: 这是一个用于修改子 Widget 布局约束的 ProxyWidget 子类。它在渲染树中修改子元素的布局信息,例如 Positioned 和 Align 等都是 ParentDataWidget 的子类,用于指定子元素的位置和对齐方式。
  • InheritedWidget: 这是一种特殊类型的 ProxyWidget,它允许在 Widget 树中向下传递共享的数据,而不需要显式地传递。当 InheritedWidget 更新时,其子孙节点会自动重新构建。适用于需要在多个部分之间共享数据的情况,如主题、语言等。

5. Widget树

Widget树的概念

在Flutter中,Widget 树是指由各种不同类型的Widget构成的层次结构。每个Widget描述了用户界面的一部分,可以是一个简单的元素,也可以是一个复杂的组合。这些Widget通过嵌套关系形成了一个树状结构,被称为Widget树。这种嵌套关系定义了界面中各个部分的排列和组织方式。

Widget树是构建用户界面的基本模型。当 Flutter 应用程序运行时,它会从一个 根Widget 开始,然后逐级构建出整个界面。每个Widget都有一个与之相关联的Element,负责管理底层的渲染树。渲染树最终会被转化为可视的UI元素,显示在屏幕上。

Widget树的特点

嵌套关系Widget 树的节点由各种不同类型的 Widget 组成,这些 Widget 可以嵌套在彼此内部,形成层次结构。

不可变性Widget 本身是 不可变 的,一旦创建就不能再进行修改。如果需要更新界面,通常是通过创建新的Widget来替换旧的Widget。

构建方式: 构建 Widget 树通常是通过构建方法来完成的。在构建方法中,你可以创建和组合不同的 Widget,从而构建出整个界面。

热重载: Flutter支持热重载,这意味着你可以在不重新启动应用程序的情况下快速修改和查看界面的变化。在热重载期间,Flutter会比较新旧Widget树的差异,并尽可能地保留应用程序的状态。

响应式: Flutter的界面是响应式的,意味着当数据发生变化时,相关的Widget会自动更新。这是通过在StatefulWidget 中管理可变状态来实现的。

F. 附录

F.1 Widget类源码

abstract class Widget extends DiagnosticableTree {/// Initializes [key] for subclasses.const Widget({ this.key });/// Controls how one widget replaces another widget in the tree.////// If the [runtimeType] and [key] properties of the two widgets are/// [operator==], respectively, then the new widget replaces the old widget by/// updating the underlying element (i.e., by calling [Element.update] with the/// new widget). Otherwise, the old element is removed from the tree, the new/// widget is inflated into an element, and the new element is inserted into the/// tree.////// In addition, using a [GlobalKey] as the widget's [key] allows the element/// to be moved around the tree (changing parent) without losing state. When a/// new widget is found (its key and type do not match a previous widget in/// the same location), but there was a widget with that same global key/// elsewhere in the tree in the previous frame, then that widget's element is/// moved to the new location.////// Generally, a widget that is the only child of another widget does not need/// an explicit key.////// See also://////  * The discussions at [Key] and [GlobalKey].final Key? key;/// Inflates this configuration to a concrete instance.////// A given widget can be included in the tree zero or more times. In particular/// a given widget can be placed in the tree multiple times. Each time a widget/// is placed in the tree, it is inflated into an [Element], which means a/// widget that is incorporated into the tree multiple times will be inflated/// multiple times.Element createElement();/// A short, textual description of this widget.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;}bool operator ==(Object other) => super == other;int get hashCode => super.hashCode;/// Whether the `newWidget` can be used to update an [Element] that currently/// has the `oldWidget` as its configuration.////// An element that uses a given widget as its configuration can be updated to/// use another widget as its configuration if, and only if, the two widgets/// have [runtimeType] and [key] properties that are [operator==].////// If the widgets have no key (their key is null), then they are considered a/// match if they have the same type, even if their children are completely/// different.static bool canUpdate(Widget oldWidget, Widget newWidget) {return oldWidget.runtimeType == newWidget.runtimeType&& oldWidget.key == newWidget.key;}// Return a numeric encoding of the specific `Widget` concrete subtype.// This is used in `Element.updateChild` to determine if a hot reload modified the// superclass of a mounted element's configuration. The encoding of each `Widget`// must match the corresponding `Element` encoding in `Element._debugConcreteSubtype`.static int _debugConcreteSubtype(Widget widget) {return widget is StatefulWidget ? 1 :widget is StatelessWidget ? 2 :0;}
}

相关文章:

Flutter源码分析笔记:Widget类源码分析

Flutter源码分析笔记 Widget类源码分析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132259681 【介绍】&#x…...

PyTorch 微调终极指南:第 2 部分 — 提高模型准确性

一、说明 如今,在训练深度学习模型时,通过在自己的数据上微调预训练模型来迁移学习已成为首选方法。通过微调这些模型,我们可以利用他们的专业知识并使其适应我们的特定任务,从而节省宝贵的时间和计算资源。本文分为四个部分&…...

MySQL数据库----------安装anaconda---------python与数据库的链接

作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 ​🎂 作者介绍: 🎂🎂 🎂 🎉🎉&#x1f389…...

nuxt页面布局

nuxt页面默认布局文件在layouts目录下default.vue&#xff0c;可将页面的头部和脚部提取出来&#xff0c;形成布局页&#xff0c;将主内容区域的内容替换成<nuxt />。附default.vue代码&#xff1a; <template><div class"app-container"><div…...

mac编译ffmpeg

- code&#xff1a; git clone https://git.ffmpeg.org/gitweb/ffmpeg.git - 编译安装 https://trac.ffmpeg.org/wiki/CompilationGuide - 使用homebrew安装dependency brew install automake fdk-aac git lame libass libtool libvorbis libvpx \ opus sdl shtool texi2ht…...

如何让你的图片服务也有类似OSS的图片处理功能

原文链接 前言 有自己机房的公司一般都有一套存储系统用于存储公司的图片、视频、音频、文件等数据&#xff0c;常见的存储系统有以NAS、FASTDFS为代表的传统文件存储&#xff0c;和以Minio为代表的对象存储系统&#xff0c;随着云服务的兴起很多公司逐渐将数据迁移到以阿里云…...

Oracle PL/SQL 类型(Type):索引表、嵌套表、变长数组、pipelined 管道

1、Oracle 新建员工表和部门表.sql。 集合类型 1、Oracle 集合是相同类型元素的组合&#xff0c;在集合中&#xff0c;使用唯一的下标来标识其中的每个元素&#xff0c;与 Java 的 List 很像。 2、常用集合方式&#xff1a; 类型语法下标元素个数初始值.extend能否存在DB中…...

Web 服务器 -【Tomcat】的简单学习

Tomcat1 简介1.1 什么是Web服务器 2 基本使用2.1 下载2.2 安装2.3 卸载2.4 启动2.5 关闭2.6 配置2.7 部署 3 Maven创建Web项目3.1 Web项目结构3.2 创建Maven Web项目 4 IDEA使用Tomcat4.1 集成本地Tomcat4.2 Tomcat Maven插件 Tomcat 1 简介 1.1 什么是Web服务器 Web服务器是…...

armbian使用1panel快速部署部署springBoot项目后端

文章目录 前言环境准备实现步骤第一步&#xff1a;Armbian安装1panel第二步&#xff1a;安装数据库第三步&#xff1a;查看数据库容器重要信息【重要】查看容器所在的网络查看容器连接地址 第四步&#xff1a;项目配置和打包第五步:构建项目镜像 前言 这里只是简单记录部署spr…...

Streamlit 讲解专栏(八):图像、音频与视频魔法

文章目录 1 前言2 st.image&#xff1a;嵌入图像内容2.1 图像展示与描述2.2 调整图像尺寸2.3 使用本地文件或URL 3 st.audio&#xff1a;嵌入音频内容3.1 播放音频文件3.2 生成音频数据播放 4 st.video&#xff1a;嵌入视频内容4.1 播放视频文件4.2 嵌入在线视频 5 结语&#x…...

python使用装饰器记录方法耗时

思路 python使用修饰器记录方法耗时&#xff0c;目的是每当方法执行完后&#xff0c;可以记录该方法耗时&#xff0c;而不需要在每个方法的执行前后&#xff0c;去创建一个临时变量&#xff0c;来记录耗时。 方式一&#xff08;不推荐&#xff09;&#xff1a; 在每个方法的…...

JavaWeb课程学习--Day01

HTML 建立css文件&#xff1a; css使用方式&#xff1a; <span>...</span>无语意包裹标签 css中的三种选择器&#xff1a; 注意&#xff1a;播放视音频时要留出播放空间 盒子模型&#xff1a; 表格标签&#xff1a; 以上表格&#xff1a; 表单标签&#xff1a; 表…...

Spring Boot单元测试使用MockBean注解向Service注入Mock对象

1. 背景介绍 我们在测试时有一个Service&#xff0c;我们需要测试Service&#xff0c;但Service内部依赖ServiceA、ServiceB&#xff0c;此时我们希望Mock ServiceA&#xff0c;ServiceB 注入真实对象。 class Service {private ServiceA A;private ServiceB B;public int me…...

Java中使用instanceof判断对象类型

记录&#xff1a;470 场景&#xff1a;Java中使用instanceof判断对象类型。例如在解析JSON字符串转换为指定类型时&#xff0c;先判断类型&#xff0c;再定向转换。在List<Object>中遍历Object时&#xff0c;先判断类型&#xff0c;再定向转换。 版本&#xff1a;JDK 1…...

postman测试后端增删改查

目录 一、本文介绍 二、准备工作 &#xff08;一&#xff09;新建测试 &#xff08;二&#xff09;默认url路径查看方法 三、增删改查 &#xff08;一&#xff09;查询全部 &#xff08;二&#xff09;增加数据 &#xff08;三&#xff09;删除数据 &#xff08;四&…...

根据源码,模拟实现 RabbitMQ - 通过 SQLite + MyBatis 设计数据库(2)

目录 一、数据库设计 1.1、数据库选择 1.2、环境配置 1.3、建库建表接口实现 1.4、封装数据库操作 1.5、针对 DataBaseManager 进行单元测试 一、数据库设计 1.1、数据库选择 MySQL 是我们最熟悉的数据库&#xff0c;但是这里我们选择使用 SQLite&#xff0c;原因如下&am…...

1、基于 CentOS 7 构建 LVS-DR 群集。 2、配置nginx负载均衡

一、基于CentOS7和、构建LVS-DR群集 准备四台虚拟机 ip作用192.168.27.150客户端192.168.27.151LVS192.168.27.152RS192.168.27.152RS 关闭防火墙 [rootlocalhost ~]# systemctl stop firewalld安装ifconfig yum install net-tools.x86_64 -y1、DS上 1.1 配置LVS虚拟IP …...

android 如何分析应用的内存(十七)——使用MAT查看Android堆

android 如何分析应用的内存&#xff08;十七&#xff09;——使用MAT查看Android堆 前一篇文章&#xff0c;介绍了使用Android profiler中的memory profiler来查看Android的堆情况。 如Android 堆中有哪些对象&#xff0c;这些对象的引用情况是什么样子的。 可是我们依然面临…...

Spring 使用注解储存对象

文章目录 前言存储 Bean 对象五大注解五大注解示例配置包扫描路径读取bean的示例 方法注解 Bean Bean 命名规则重命名 Bean 前言 通过在 spring-config 中添加bean的注册内容&#xff0c;我们已经可以实现基本的Spring读取和存储对象的操作了&#xff0c;但在操作中我们发现读…...

一、初始 Spring MVC

文章目录 一、回顾 MVC 模式二、初始 Spring MVC2.1 Spring MVC 核心组件2.1.1 前端控制器&#xff08;DispatcherServlet&#xff09;2.1.2 处理器映射器&#xff08;HandlerMapping&#xff09;2.1.3 处理器适配器&#xff08;HandlerAdapter&#xff09;2.1.3 后端控制器&am…...

模拟法解题的思路与算法分享

我们先来看思路与算法&#xff1a; 使用变长数组对栈进行模拟。 如果操作是 &#xff0c;那么访问数组的后两个得分&#xff0c;将两个得分之和加到总得分&#xff0c;并且将两个得分之和入栈。如果操作是 D&#xff0c;那么访问数组的最后一个得分&#xff0c;将得分乘以 2 …...

DAY 44 预训练模型

知识点回顾&#xff1a; 预训练的概念常见的分类预训练模型图像预训练模型的发展史预训练的策略预训练代码实战&#xff1a;resnet18 &#xff08;一&#xff09;预训练的概念 我们发现准确率最开始随着epoch的增加而增加。随着循环的更新&#xff0c;参数在不断发生更新。 所以…...

Redis线程安全深度解析:单线程模型的并发智慧

Redis线程安全深度解析&#xff1a;单线程模型的并发智慧 引言&#xff1a;Redis的线程模型迷思 “Redis是单线程的”——这个广为流传的说法既正确又不完全正确。Redis的线程安全机制实际上是一套精心设计的并发控制体系&#xff0c;它既保持了单线程的简单性&#xff0c;又…...

北京大学肖臻老师《区块链技术与应用》公开课:12-BTC-比特币的匿名性

文章目录 1.比特币的匿名性不是真的匿名&#xff0c;相当于化名&#xff0c;现金是真的匿名&#xff0c; 2.如果银行用化名的话和比特币的匿名哪个匿名性更好&#xff1f; 银行匿名性比比特币好&#xff0c;因为比特币的区块链的账本是完全公开的&#xff0c;所有人都可以查&am…...

React Native图片预加载:让你的应用图片预览像德芙一样丝滑

写在前面:一张图片引发的性能血案 你有没有遇到过这种情况?——用户疯狂滑动你的React Native图片列表,结果图片加载慢得像蜗牛,甚至出现空白闪烁?等到图片终于加载出来,用户早就失去耐心,愤然退出…… 但你知道吗?这个问题只需要几行代码就能解决! 比如,使用reac…...

Codeforces Round 1025 (Div. 2) B. Slice to Survive

Codeforces Round 1025 (Div. 2) B. Slice to Survive 题目 Duelists Mouf and Fouad enter the arena, which is an n m n \times m nm grid! Fouad’s monster starts at cell ( a , b ) (a, b) (a,b), where rows are numbered 1 1 1 to n n n and columns 1 1 1 t…...

Xilinx FPGA 重构Multiboot ICAPE2和ICAPE3使用

一、FPGA Multiboot 本文主要介绍基于IPROG命令的FPGA多版本重构&#xff0c;用ICAP原语实现在线多版本切换。需要了解MultiBoot Fallback点击链接。 如下图所示&#xff0c;ICAP原语可实现flash中n1各版本的动态切换&#xff0c;在工作过程中&#xff0c;可以通过IPROG命令切…...

Android 视图系统入门指南

1. View&#xff1a;界面的最小单位 本质&#xff1a;屏幕上的一个矩形区域&#xff0c;能显示内容或接收触摸。比喻&#xff1a;就像乐高积木&#xff0c;是组成界面的最小单位。常见子类&#xff1a; TextView&#xff08;文字积木&#xff09;、Button&#xff08;按钮积木…...

容器安全最佳实践:云原生环境下的零信任架构实施

&#x1f4cb; 目录 引言&#xff1a;容器安全的重要性零信任架构基础理论云原生环境的安全挑战容器安全威胁模型分析零信任架构在容器环境中的实施关键技术组件与工具安全策略与最佳实践监控与响应机制案例研究与实施路径未来发展趋势 引言 随着容器技术和云原生架构的快速…...

Qt Test功能及架构

Qt Test 是 Qt 框架中的单元测试模块&#xff0c;在 Qt 6.0 中提供了全面的测试功能。 一、主要功能 核心功能 1. 单元测试框架 提供完整的单元测试基础设施 支持测试用例、测试套件的组织和执行 包含断言宏和测试结果收集 2. 测试类型支持 单元测试&#xff1a;对单个函…...