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;}
}

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

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

相关文章

TestNG和Junit5测试框架梳理

一、testNG 1. testNG优势 注解驱动: TestNG 使用注解来标识测试方法、测试类和配置方法,使得测试更具可读性。 并行执行: TestNG 支持多线程并行执行测试,可以加速测试套件的执行。 丰富的配置: 可以通过 XML 配置文…

Qt下载安装及配置教程

进入qt中文网站:https://www.qt.io/zh-cn/ 下载开源版 往下滑,下载Qt在线安装程序 它已经检测出我的是windows系统,直接点击download就好。如果是其它的系统,需要找到对应自己系统的安装包。 然后跟网速有关,等…

Gitlab CI/CD笔记-第三天-使用主机docker in docker 进行构建并push镜像。

一、啥叫docker in docker 就是允许的镜像里头有一个docker,但这个docekr镜像只有docker的cli和/var/lib/docker.sock的套接字,没有允许build.然后里头又运行了一个docker,这个docker有build的能力,此时构建时就是里头的docker使用外部的dock…

登录验证码实现

Hutool代码改造 Hutool 有参考文档&#xff1b;很多工具类&#xff1b;把一些功能都封装好&#xff1b;都不用你自己去写&#xff1b;直接调用它的工具类 它这里会详细告诉你引入方式Hutool <dependency><groupId>cn.hutool</groupId><artifactId>hu…

STM32F429IGT6使用CubeMX配置SPI通信(W25Q256芯片)

1、硬件电路 需要系统性的看一下W25Q256芯片手册 2、设置RCC&#xff0c;选择高速外部时钟HSE,时钟设置为180MHz 3、配置SPI 4、生成工程配置 5、相关代码 #define sFLASH_ID 0XEF4019 // W25Q256#define SPI_FLASH_PageSize 256 #define SPI_FLASH_PerWritePageSize 256#def…

《雷达像智能识别对抗研究进展》阅读记录

&#xff08;1&#xff09;引言 ​ 神经网络通常存在鲁棒性缺陷&#xff0c;易受到对抗攻击的威胁。攻击者可以隐蔽的诱导雷达智能目标识别做出错误预测&#xff0c;如&#xff1a; ​ a图是自行车&#xff0c;加上对抗扰动后神经网络就会将其识别为挖掘机。 &#xff08;2&a…

【Quarkus技术系列】打造基于Quarkus的云原生微服务框架实践(1)

前提介绍 本系列文章主要讲解如何基于Quarkus技术搭建和开发"专为Kubernetes而优化的Java微服务框架"的入门和实践&#xff0c;你将会学习到如何搭建Quarkus微服务脚环境及脚手架&#xff0c;开发Quarkus的端点服务&#xff0c;系统和应用层级的配置介绍与Quarkus的…

单芯片3路CC管理的VR转接器解决方案

VR眼镜即VR头显&#xff0c;也称虚拟现实头戴式显示设备&#xff0c;随着元宇宙概念的传播&#xff0c;VR眼镜的热度一直只增不减&#xff0c;但是头戴设备的续航一直被人诟病&#xff0c;如果增大电池就会让头显变得笨重影响体验&#xff0c;所以目前最佳的解决方案还是使用VR…

C# BeginInvoke 加 EndInvoke实现异步操作

1、定义一个委托 delegate long MyDel(int first, int second); 2、 需异步操作的函数 static int sum(int x,int y) {Console.WriteLine("InSide Sum1");Thread.Sleep(1000);Console.WriteLine("InSide Sum2");return x y;} 3、回调方法…

[HDLBits] Exams/m2014 q3

Consider the function f shown in the Karnaugh map below. Implement this function. d is dont-care, which means you may choose to output whatever value is convenient. //empty

gitui 解决 git error:Bad credentials.

问题描述 cat .git/config """ [remote "origin"]url gitgitcode.net:xxx.gitfetch refs/heads/*:refs/remotes/origin/* """ls -lh ~/.ssh/ """ -rw------- 1 z z 2.6K 8月 12 15:04 id_rsa -rw-r--r-- 1 z z 56…

学习左耳听风栏目90天——第六天 6/90(学习左耳朵耗子的工匠精神,对技术的热爱)【如何拥有技术领导力】

学习左耳听风栏目90天——第六天 6/90&#xff08;学习左耳朵耗子的工匠精神&#xff0c;对技术的热爱&#xff09;【如何拥有技术领导力】

【第358场周赛】限制条件下元素之间的最小绝对差,Java解密。

LeetCode 第358场周赛 恒生专场。 文章目录 剑指Offer:限制条件下元素之间的最小绝对差示例:限制:解题思路:剑指Offer:限制条件下元素之间的最小绝对差 【题目描述】 给你一个下标从 0 开始的整数数组 nums 和一个整数 x 。 请你找到数组中下标距离至少为 x 的两个元素的…

虚拟机内搭建CTFd平台搭建及CTF题库部署,局域网内机器可以访问

一、虚拟机环境搭建 1、安装docker、git、docker-compose ubuntu&#xff1a; sudo apt-get update #更新系统 sudo apt-get -y install docker.io #安装docker sudo apt-get -y install git #安装git sudo apt-get -y install python3-pip #安装pip3 sudo pip install dock…

SQL笔记

最近的工作对SQL的应用程度较高&#xff0c;而且写的sql类型基本没怎么涉及过&#xff0c;把用到的几个关键字记录下。 使用环境&#xff1a;达梦数据库 达梦数据库有个特点&#xff0c;他有一个叫模式的说法&#xff0c;在图形化工具里直接点击创建查询窗口&#xff0c;不用像…

Kubeadm安装K8s集群

一、硬件环境 准备3台Linux服务器&#xff0c;此处用Vmware虚拟机。 主机名CPU内存k8smaster2核4Gk8snode12核4Gk8snode22核4G 二、系统前置准备 配置三台主机的hosts文件 cat << EOF > /etc/hosts 192.168.240.130 k8smaster 192.168.240.132 k8snode1 192.168.…

Sql奇技淫巧之ROWNUM伪列

ROWNUM伪列 ROWNUM是一个伪列&#xff0c;它是根据每次查询的结果动态生成的一列递增编号&#xff0c;表示 Oracle 从表中选择该行的顺序&#xff0c;选择的第一行ROWNUM为1&#xff0c;第二行ROWNUM为2&#xff0c;以此类推。 注意1&#xff1a; ROWNUM伪列是在WHERE子句之…

torch.profiler

什么是torch.profiler PyTorch Profiler 是一个工具&#xff0c;它允许在训练和推理期间收集性能指标。Profiler 的上下文管理器 API 可用于更好地了解哪些模型操作最昂贵&#xff0c;检查它们的输入形状和调用堆栈&#xff0c;研究设备内核活动并可视化执行跟踪。 性能指标&…

腾讯出品Pag动画框架在Android端的使用-初级

Pag动画框架作为一个第三方框架&#xff0c;它的优缺点与Lottie是相似&#xff0c;此处不过多赘述。如果你们的项目中打算用了&#xff0c;肯定是经过了一定的调研的。Pag动画框架分几个版本&#xff0c;有免费的有收费的。我们目前用的社区免费版&#xff0c;只用来展示Pag动画…

项目实战 — 消息队列(8){网络通信设计②}

目录 一、客户端设计 &#x1f345; 1、设计三个核心类 &#x1f345; 2、完善Connection类 &#x1f384; 读取请求和响应、创建channel &#x1f384; 添加扫描线程 &#x1f384; 处理不同的响应 &#x1f384; 关闭连接 &#x1f345; 3、完善Channel类 &#x1f384; 编…