Element复用:StatefulWidget修改和key

2023-10-27

在Flutter中,Widget的功能是“描述一个UI元素的配置数据”,即,Widget其实并不是表示最终绘制在设备屏幕上的显示元素,而只是显示元素的一个配置数据。Flutter中真正代表屏幕上显示元素的类是Element
若类比于编程语言,Widget就像是一个抽象类,而Element才是具体的类实例。
因此,一个Widget对象可能会对应多个Element对象。

渲染流程

  1. 根据用户代码创建Widget树。
  2. 由Widget树创建对应的Element树。
  3. 由Element树生成Render树。

最后,Render树经过布局、绘制等,在界面上显示出来。
由于具体的显示都是Element控制,因此可以认为Element是显示在界面上的元素。

Element的复用

出于效率原因,Element是可复用的。
对于新的一帧,Widget会判断每个Element是否可复用。若是,则保留Element,并用新的Widget配置来更新;否则,则创建新的Element。
也就是说,对于一帧新画面上的Element,要么更新,要么重建。
Widget负责判断Element是否可复用。Widget的判断源码为:

static bool canUpdate(Widget oldWidget, Widget newWidget) {
  return oldWidget.runtimeType == newWidget.runtimeType
      && oldWidget.key == newWidget.key;
}

判断条件很简单,根据前后帧的两个Widget配置:

  1. runtimeType相等
  2. key相等

若两个条件都为true,则表示Element可复用,只使用newWidget来更新Element即可;否则,则表示Element不可复用,需直接创建。
其中:

  1. runtimeType为运行时类型,即该Widget的类。例如,1/2/3的runtimeType为int,“1”/“2”/"3"的runtimeType为String,自定义的Widget其runtimeType为具体的自定义类型。仅仅指类型,不涉及具体的数据。
  2. key即用户传入的key。若用户没有传入,则为null。(null == null)返回true。

实例: StatelessWidget

定义一个StatelessWidget:

class StatelessW extends StatelessWidget {
  String text = '';

  StatelessW(this.text, {Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(text);
  }
}

如上,该StatelessW接收1个父组件传入的String。
进行如下操作:

  1. StatelessW sw = StatelessW(‘text1’),并放在某个容器中。框架的对应逻辑为:

    • 为Widget设置数据text = ‘text1’。
    • 该Widget对应的Element不存在,故会创建新的Element。

    此时,界面上显示文本’text1’。

  2. sw = StatelessW(‘text2’)。框架的对应逻辑为:

    • 为Widget设置数据text = ‘text2’。

    • 该Widget对应的Element存在,于是进入canUpdate()判断:

      • oldWidget.runtimeType为StatelessW,newWidget.runtimeType为StatelessW,相等
      • oldWidget.key为null,newWidget.key为null,相等

      于是,Element判定为可复用,保留。

    • 使用newWidget来更新复用的Element。由于newWidget中text = ‘text2’,故Element要显示的text属性会被更新为’text2’。

    此时,界面上显示文本’text2’。

  3. sw = StatelessW(‘text3’, key: UniqueKey())。框架的对应逻辑为:

    • 为Widget设置数据text = ‘text3’。

    • 该Widget对应的Element存在,于是进入canUpdate()判断:

      • oldWidget.runtimeType为StatelessW,newWidget.runtimeType为StatelessW,相等
      • oldWidget.key为null,newWidget.key为一个随机值,不相等

      于是,Element判定为可不复用,需创建新的Element。

    • 创建新的Element。由于newWidget中text = ‘text3’,故新的Element中要显示的text属性是’text3’。

    此时,界面上显示文本’text3’。

实例: StatefulWidget

定义一个StatefulWidget:

class StatefulW extends StatefulWidget {
  String text = '';

  StatefulW(this.text, {Key key}) : super(key: key);

  @override
  _StatefulWState createState() => _StatefulWState(text);
}

class _StatefulWState extends State<StatefulW> {
  String sText = '';

  _StatefulWState(this.text) {
    this.sText = widget.text;
  }

  @override
  Widget build(BuildContext context) {
    return Text(sText);
  }
}

如上,该StatefulW接收1个父组件传入的String。
进行如下操作:

  1. StatefulW sw = StatefulW(‘text1’),并放在某个容器中。框架的对应逻辑为:

    • 为Widget设置数据text = ‘text1’。
    • 该Widget对应的Element不存在,故会创建新的Element。
    • Element创建时,内部的_StatefulWState会一同创建。_StatefulWState内部定义了一个sText,创建时会被赋予初值’text1’。

    显示依赖的是_StatefulWState。此时,界面上显示文本’text1’。

  2. sw = StatefulW(‘text2’)。框架的对应逻辑为:

    • 为Widget设置数据text = ‘text2’。

    • 该Widget对应的Element存在,于是进入canUpdate()判断:

      • oldWidget.runtimeType为StatefulW,newWidget.runtimeType为StatefulW,相等
      • oldWidget.key为null,newWidget.key为null,相等

      于是,Element判定为可复用,保留。其内部的_StatefulWState也随之保留。

    • 使用newWidget来更新复用的Element。由于newWidget中text = ‘text2’,故Element的text属性会被更新为’text2’。

    • 然而,_StatefulWState被保留,故不会再次进入构造函数。于是_StatefulWState中的sText属性依然为’text1’。

    显示依赖的是_StatefulWState。此时,尽管StatefulW的text属性已经更新为’text2’,但_StatefulWState中的sText属性依然为’text1’,故界面上显示文本’text1’。

  3. sw = StatefulW(‘text3’, key: UniqueKey())。框架的对应逻辑为:

    • 为Widget设置数据text = ‘text3’。

    • 该Widget对应的Element存在,于是进入canUpdate()判断:

      • oldWidget.runtimeType为StatefulW,newWidget.runtimeType为StatefulW,相等
      • oldWidget.key为null,newWidget.key为一个随机值,不相等

      于是,Element判定为可不复用,需创建新的Element。

    • 创建新的Element。由于newWidget中text = ‘text3’,故新的Element中text属性是’text3’。

    • Element创建时,内部的_StatefulWState会一同创建。_StatefulWState内部定义了一个sText,创建时会被赋予初值’text3’。

    显示依赖的是_StatefulWState。此时,界面上显示文本’text3’。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Element复用:StatefulWidget修改和key 的相关文章

  • Flutter:致命错误:回调查找失败! (带有音频播放器包)

    以下代码片段是按钮 单击该按钮会发出短促的蜂鸣声 FlatButton onPressed gt final player new AudioCache player play note1 wav child Text Click to d
  • Flutter Firebase 身份验证 currentUser() 返回 null

    这是关于 Flutter Firebase 身份验证插件的 我试图在创建新用户后发送验证电子邮件 但 sendEmailVerification 内部使用 currentUser 这对我来说似乎是一个错误 但为了以防万一 我在 stacko
  • 如何更改文本字段颤动内部的值?

    我有一个TextEditingController如果用户单击按钮 它就会填写信息 我似乎不知道如何更改 a 中的文本Textfield or TextFormField 有解决办法吗 只需更改text财产 TextField contro
  • ListView 和快照 - 错误 - 错误状态:DocumentSnapshotPlatform 中不存在字段[重复]

    这个问题在这里已经有答案了 我对快照和 ListView 有一个小问题 到目前为止 它运行得很好 但自从我更新了 flutter 和 Dart 后 我 收到了一个错误 构建 StreamBuilder gt 时抛出以下 StateError
  • Flutter 中的 Android 许可证

    4 天前一切正常 我进行了更新 许可证停止通过 我到目前为止所做的事情 检查了工具过时的东西 gt 不起作用 flutter doctor android licenses gt 不起作用 sdkmanager licenses gt 不起
  • 没有脚手架的 DefaultTabController?

    我正在尝试使用DefaultTabController在一些小部件的中间 所以我的TabBar不能在AppBar并且必须关闭一些小部件 所以我的问题是当我使用时TabBarView它崩溃了 这是一个 Flutter 示例的示例 但没有找到如
  • 如何在flutter项目中使用http拦截器?

    我必须向我的所有 Api 添加标头 有人告诉我为此使用 http 拦截器 但我无法理解如何做到这一点 因为我是颤振的新手 谁能帮我举个例子吗 您可以使用http 拦截器 https pub dev packages http interce
  • 如何从 BottomNavigationBar 中删除图标?

    我只需要 BottomNavigationBarItem 中的标签 但我找不到删除它们的方法 您可以隐藏标签showSelectedLabels and showUnselectedLabels设置为 false 但图标没有等效项 构造函数
  • 如何在flutter中绕过SSL证书验证?

    如何在flutter中绕过SSL证书验证 错误 握手异常 客户端中的握手错误 操作系统错误 CERTIFICATE VERIFY FAILED 自签名证书 handshake cc 345 您需要配置 HttpService 以使用自签名
  • 如何让“material-dropdown-select”显示当前模型值

    使用 AngularDart 角度组件 https github com dart lang angular components 我需要创建一个下拉列表 其中填充了一小部分项目 使其工作 并自动设置为模型中对象的当前选择 尚未使其工作 我
  • Flutter - 构建失败并出现异常

    当我启动我的应用程序时 我收到此错误消息 自上次运行以来我没有进行任何更改 当时一切都很好 有人知道如何解决这个问题吗 谢谢 FAILURE Build failed with an exception 什么地方出了错 无法确定任务 app
  • dart javascript 编译器 (dart2js) 如何工作?

    Dart 在其自己的 Dart VM 中运行 但您可以将其编译为现代优化的 JavaScript 但这是如何运作的呢 网上有任何文章或论文解释该过程吗 我想知道这是否是一个简单直接的元素与元素匹配 仅耗时开发 处理 或者 Dart 的某些元
  • 谷歌地图颤动检查点是否在多边形内

    我正在使用 google maps flutter 插件开发 flutter 项目 我想检查用户位置是否位于我在地图上创建的多边形内 有一个简单的方法使用 JavaScript api con tainsLocation 方法 但对于 fl
  • 如何更改 ElevatedButton 颜色或阴影 Flutter

    我当时用的是RaisedButton直到 Flutter 弃用了它 我们不能再使用它了 有一个建议说 使用ElevatedButton相反 所以我尝试使用它 但我看不到类似的属性color elevation focusColor etc
  • 如何在 Flutter Provider 中删除 StreamController 中的数据?

    我正在使用provider来构建我的应用程序 因此数据被添加到StreamController中 每次刷新我的应用程序时 它都会调用API 然后将数据推送到StreamController 问题是如何在替换之前删除数据新的那一个 contr
  • 自定义卡片形状 Flutter SDK

    我在 Flutter 上使用 GridView 开发了一个应用程序 GridView 项目是卡片 默认卡片形状是半径为 4 的矩形 我知道 Card Widget 有 shape 属性 并且它需要 ShapeBorder 类 但我无法找到如
  • flutter 中 sqlite 中的多个参数

    我想知道如何将多个参数传递给 sqllite 中的原始查询 我的代码如下 query async get a reference to the database Database db await DatabaseHelper instan
  • 已发布的 Flutter 应用程序在启动时崩溃

    编辑 此问题的解决方案是将您的 flutter 版本升级到较新的 dev 版本 then 1 7 0 您还可以上传单独的 APK 版本 但我个人不喜欢这个选项 请确保您没有从 flutter github 开发存储库下载 错误的构建 因为那
  • 实施 ChangeNotifier 与 StateNotifier

    我很熟悉Provider https pub dev packages provider打包并将其与ChangeNotifier 假设我有 3 个 getter 和具有不同功能的方法 切换加载 切换图像加载 切换 ObsecurePassw
  • 如何在 Dart 分析器/source-gen 中从某些元素获取 AstNode?

    我在用着source gen解析一些Dart文件 通过Dartanalyzer 我正在延长GeneratorForAnnotation lt gt 以及重写方法FutureOr

随机推荐

  • 接口用例设计与常见接口问题汇总

    一 接口用例设计 一 接口测试用例可以从功能 性能 安全三方面进行入手 设计 详情参看以下思维导图 二 接口常见问题汇总 一 接口技术层面 1 输入参数验证校验不全面 如 1 1入参数据类型长度边界 范围边界 1 2 入参数据内容 成员内容
  • 毕业论文 latex 引用 作者大小写问题

    1 上面这种形式可能不是学校要求的 2 如果是需要上面这种形式 3 gbt7714 2005 bst对于这个模板文件 FUNCTION format names String Entry format names String names
  • 2022年计算机考研复试基本分数线多少呢?

    2022计算机考研初试结束之后 很多考生在搜索 考研复试基本分数线 的相关信息 实际上官方暂未公布 预计在2022年3月上旬公布 如您想知道2022年计算机考研复试基本分数线 建议跟着小编往下看吧 计算机考研复试基本分数线的另一种说法是 计
  • 最新版android studio 4.1 开启gradle offline

    Android studio build 或者运行app的时候就重新下载依赖等文件 是因为没有开启offline模式 新版Android studio 之前突然找不到了 ok 点击选中之后 就不会每次都下载了 节省了大量时间
  • VC++ MapWinGis篇(创建图层)

    MapWinGis控件的引用 import MapWinGIS ocx rename IImage gisIImage rename ImageType gisImageType rename Point gisPoint using na
  • 《程序员代码面试指南第二版》Python实现(个人读书笔记)

    说明 最近在读左神的书 程序员代码面试指南 IT名企算法与数据结构题目最优解 第二版 以及看了一些左神的基础 进阶 高频等视频课程 为了记录自己的学习成果 并且方便以后查看 将自己的想法与使用python实现的代码记录在此博客 视频 基础
  • i.mx287学习笔记7-与图灵机器人对话

    上面是我的微信和QQ群 欢迎新朋友的加入 1 创建QT界面 目前界面比较简单 就是两个按键加两个文本窗口 第一个文本窗口用于输入聊天信息 第二个文本窗口用于显示图灵的返回信息 send按键发送聊天信息 clear按键清除文本框内容 2 修改
  • STM32 基于Keil IDE 开发引用 Astyle 第三方工具格式化插件

    目录 概述 一 使用方法 二 STM32CubeMx配置 三 Examples 四 运行结果 五 总结 概述 本篇文章介绍如何使用Keil IDE 引用Astyle 第三方工具格式化代码 官网 http astyle sourceforge
  • 软件外包开发项目管理工具

    随着软件项目规模越来越大 功能设计也越来越复杂 参与的人越来越多 为了保障项目开发质量和交付质量 项目经理需要使用项目管理工具来提高项目质量 确保项目交付时间和质量 今天和大家分享几款好用的项目管理工具 希望对大家有所帮助 北京木奇移动技术
  • 请求和响应的装饰——装饰器设计模式

    一 装饰器设计模式 即使没有某一个对象的类的源代码 甚至即便这个类是声明为final的 Decorator模式和Wrapper模式都允许装饰或者包装 说白了 就是修改 这个对象的行为 Decorator模式适用于无法使用继承的情况 比如 某
  • xml的学习和使用python解析读取xml文件

    1 XML的介绍 XML 指可扩展标记语言 EXtensible Markup Language 和json类似也是用于存储和传输数据 还可以用作配置文件 类似于HTML超文本标记语言 但是HTML所有的标签都是预定义的 而xml的标签是自
  • Apache ShenYu(神禹) 网关

    Apache ShenYu 神禹 网关 项目中的服务调用监控链 ShenYu网关 回顾Zuul 功能 对请求的路由和过滤 路由转发 将请求转发到微服务实例上 过滤器 对请求的处理进行干预 请求校验 服务聚合等 yaml配置 zuul rou
  • Java类加载器&反射

    1 类加载器 1 1类加载器 作用 负责将 class文件 存储的物理文件 加载在到内存中 1 2类加载的过程 类加载时机 创建类的实例 对象 调用类的类方法 访问类或者接口的类变量 或者为该类变量赋值 使用反射方式来强制创建某个类或接口对
  • [PyTorch][chapter 55][GAN- 2]

    前言 这里面结合纳什均衡 分析GAN损失函数优化的原理 优化目标 纳什均衡 D JS 散度 纳什均衡 G DCGAN 目录 1 纳什均衡 D 2 纳什均衡 G 3 JS 散度缺陷 一 训练方法 1 1 损失函数 1 2 训练方法 二 纳什均
  • 服务器 cpu型号怎么看,服务器cpu参数肿么看

    一 CPU大小 root idc more proc cpuinfo 可以看到详细内容或 root idc cat proc cpuinfo grep model name cat proc cpuinfo grep physical id
  • 408数据结构综合题

    数据结构综合应用题 问题 设计一个算法删除单链表L 有头结点 中的一个最小值结点 思路 用指针p从头至尾扫描链表 pre指向 p结点的前驱 用minp保存值最小的结点指针 minpre指向minp的前驱 一边扫描 一边比较 将最小值结点放到
  • 挑战35岁,重新定义体能素质与健康生活

    随着年龄的增长 我们常常被告知35岁是一个关键的节点 被认为是身体开始下滑和健康问题增多的时期 然而 我认为生理年龄并不是我们判断体能素质和健康的唯一标准 相反 我们的生活方式和日常行为在很大程度上决定了我们的身体状况和健康状况 首先 年龄
  • VUE中index.html什么时候加载的mainjs呢

    今天突然思考到一个问题 index html文件中是vue项目的主页 项目入口 那么mainjs是啥时候被index加载运行的呢 是怎么被运行的呢 1 先来看看vue项目的一个结构解析 非常感谢磊阿磊阿磊磊磊的图片 index html 主
  • prometheus部署node,server以及域名加告警

    安装prometheus 系统 root i u7jq7uyl cat etc redhat release CentOS Linux release 7 2 1511 Core 本文档只是部署单节点 要部署多个节点请参考官方federat
  • Element复用:StatefulWidget修改和key

    在Flutter中 Widget的功能是 描述一个UI元素的配置数据 即 Widget其实并不是表示最终绘制在设备屏幕上的显示元素 而只是显示元素的一个配置数据 Flutter中真正代表屏幕上显示元素的类是Element 若类比于编程语言