Widget结构(一)

embedded/2024/10/24 3:16:10/

1、概念

Widget 是 UI 控件的基本抽象,它负责描述 UI 的一部分应该如何构建。每个Widget 都有一个对应的 RenderObject,负责实际的布局和绘制工作。Widget 不直接参与布局或绘制过程;它们只是描述了如何构建用户界面的一部分,并且可以被组合起来创建更复杂的 UI。

2、Widget接口

Wiget类本身是一个抽象类,最核心的部分是定义了createElement()接口,在Flutter实际开发中,我们使用StatelessWidget和StatefulWidget间接继承Widget来实现新组件,比如创建Flutter项目时生成的示例代码。


abstract class Widget extends DiagnosticableTree {const Widget({required this.key});final Key key;Element createElement();String toStringShort() {return '$runtimeType';}void debugFillproperties(DiagnosticPropertiesBuilder properties) {super.debugFillProperties(properties);properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;}static bool canUpdate(Widget oldWidget, Widget newWidget) {return oldWidget.runtimeType == newWidget.runtimeType &&oldWidget.key == newWidget.key;}
}
  • DiagnosticableTree:诊断树,它在Flutter框架中主要用于生成诊断信息,帮助我们更好的理解程序的运行状态;

  • key:决定是否在下一次创建时复用旧的Widget,条件在canUpdate()中;

  • createElement():Flutter Framework构建UI树时,优先调用此方法生成对应节点的Element对象,Flutter Framework在调用时为隐式调用;

  • DiagnosticableTree 方法:

    方法作用
    toString()返回对象的字符串表示形式。
    toStringShort()返回对象的简短字符串表示形式。
    toStringDeep()返回对象及其子树的详细字符串表示形式。
    toStringShallow()返回对象本身的详细字符串表示形式。
    toStringProperties()返回对象的属性信息。
    debugFillProperties()填充诊断属性构建器,用于生成详细的诊断信息。
  • canUpdate()是否使用旧的Widget对象更新旧UI树上对应Element配置,如果两个Widget的runtimeType和Key同时相等,则认为它们可以更新。

3、StatelessWidget

StatelessWidget继承自Widget类重写了createElement()方法:


class Echo extends StatelessWidget {
const Echo({super.key});
StatelessElement createElement() => StatelessElement(this);
Widget build(BuildContext context) {// TODO: implement buildthrow UnimplementedError();
}
}
  • 显示文本

class Echo extends StatelessWidget {final String text;final Color backgroundColor;const Echo({super.key,required this.text,this.backgroundColor = Colors.grey,required String title});StatelessElement createElement() => StatelessElement(this);Widget build(BuildContext context) {return Center(child: Container(color: backgroundColor,child: Text(text),),);}
}
  • 调用
class _MyHomePageState extends State<MyHomePage> {Widget build(BuildContext context) {return const Echo(text: "示例文本", title: "StatelessWidget");}
}

4、StatefulWidget

StatefulWidget和StatelessWidget一样也继承自Widget类 ,StatefulWidget也重写了createElement()方法,返回的Element对象不同;而且StatefulWidget类中添加了一个新的接口createState()

  • StatefulWidget源码
abstract class StatefulWidget extends Widget {const StatefulWidget({ super.key });StatefulElement createElement() => StatefulElement(this);State createState();
}
  • StatefulElement:间接调用Element类,作为StatefulWidget的配置数据相对应,StatefulElement是Element的子类,它可以多次调用createState()来创建状态对象;
  • createState():抽象方法,必须在具体的StatefulWidget子类中实现,用于创建Stateful Widget相关的状态,State对象负责维持Widget的状态,并提供一种机制触发Widget的重新构建。

5、State

State类是与StatefulWidget一起工作的核心部分之一,当创建一个createState方法,该方法返回一个State类的实例,这个State类负责管理Widget的状态,并提供了更新UI的方法。

State中保存的状态信息可以进行如下操作:

  • Widget构建时可以被同步读取;
  • Widget生命周期可以被改变,当State发生改变时,可以手动调用build重构Widget树,以达到更新UI的目的。
5.1 State生命周期
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),useMaterial3: true,),home: const MyHomePage(),);}
}class MyHomePage extends StatelessWidget {const MyHomePage({super.key});Widget build(BuildContext context) {// return const CounterWidget();return const Text("测试文本");}
}class CounterWidget extends StatefulWidget {final int initValue;const CounterWidget({super.key, required this.initValue});State<CounterWidget> createState() => _CounterWidgetStates();
}class _CounterWidgetStates extends State<CounterWidget> {late int _counter;bool _hotReloadTrigger = false;void initState() {super.initState();_counter = widget.initValue;if (kDebugMode) {print("initState");}}Widget build(BuildContext context) {if (kDebugMode) {print("build");}// 使用 _hotReloadTrigger 来触发构建变化return Scaffold(appBar: AppBar(title: Text(_hotReloadTrigger ? 'Hot Reload Triggered' : 'Counter'),),body: Center(child: ElevatedButton(onPressed: () => setState(() => ++_counter),child: Text("$_counter"),),),);}void didUpdateWidget(covariant CounterWidget oldWidget) {super.didUpdateWidget(oldWidget);if (kDebugMode) {print("didUpdateWidget");}}void reassemble() {super.reassemble();if (kDebugMode) {print("reassemble");}// 改变属性以触发 didUpdateWidgetsetState(() {_hotReloadTrigger = !_hotReloadTrigger;// 创建新的 CounterWidget 实例以触发 didUpdateWidgetfinal newWidget = CounterWidget(initValue: widget.initValue);if (newWidget != widget) {if (kDebugMode) {print("$newWidget");}}});}void didChangeDependencies() {super.didChangeDependencies();if (kDebugMode) {print("didChangeDependencies");}}
}
  • 修改MyHomePage类,添加跳转按钮,控制台的输出日志如下:

    I/flutter ( 5101): initState
    I/flutter ( 5101): didChangeDependencies
    I/flutter ( 5101): build
    
  • 点击热重载,控制台的输出日志如下:

    I/flutter ( 5101): reassemble
    I/flutter ( 5101): build
    
  • 修改build,返回文本:

    class MyHomePage extends StatelessWidget {const MyHomePage({super.key});Widget build(BuildContext context) {// return const CounterWidget();return const Text("测试文本");}
    }
    
5.2 回调函数说明
  • build():负责构建组件的实际UI,它在以下几种情况下调用:

    • 在调用initState()didUpdateWidget()setState()didChangeDependencies()这几种方法之后;
    • 在State对象从树中一个位置移除又插入到树的其他位置之后。
  • initState():当Widget第一次插入到树中调用,执行初始化工作的最佳时机,此方法只会调用一次,之后即使组件重建也不会再次调用;

  • didChangeDependencies():当State对象的依赖发生变化时会被调用,例如当应用的主题或者语言发生变化,Flutter framework会通知Widget调用此回调;

  • reassemble():为开发调试使用,点击热重载后会调用此方法;

  • didUpdateWidget():检测Widget树某一节点是否需要更新,在新旧Widget的Key和runtimeType同时相等时就调用didUpdateWidget()

  • deactivate():当State对象暂时从树中移除但未来可能重新插入的时候调用;

  • dispose():当State对象永久从树中移除时调用,只调用一次,调用后该State对象不能再用于构建UI。


http://www.ppmy.cn/embedded/129973.html

相关文章

基于SpringBoot+Vue+uniapp的C语言在线评测系统的详细设计和实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

视频云存储/音视频流媒体视频平台EasyCVR视频汇聚平台在欧拉系统中启动失败是什么原因?

视频监控/视频集中存储/磁盘阵列EasyCVR视频汇聚平台具备强大的拓展性和灵活性&#xff0c;支持多种视频流的外部分发&#xff0c;如RTMP、RTSP、HTTP-FLV、WebSocket-FLV、HLS、WebRTC、fmp4等&#xff0c;这为其在各种复杂环境下的部署提供了便利。 安防监控EasyCVR视频汇聚平…

关于QT cmake项目添加了.ui文件build未自动生成ui_xxx.h,错误提示找不到这个头文件问题处理

文章目录 问题分析举例 问题 当我们想使用cmakelist来编译运行一个QT项目时&#xff0c;当项目中存在Ui文件时&#xff0c;我们可能会遇到ui_XXX.h头文件找不到的问题。这里我们来分析并解决一下问题。 分析 不管是在cmake下或者qmake下的ui_XXX.h都是根据XXX.ui文件自动生成…

sealed class-kotlin中的封闭类

在 Kotlin 中&#xff0c;sealed class&#xff08;密封类&#xff09;是一种特殊的类&#xff0c;用于限制继承的类的数量。密封类可以被用来表示一组有限的类型&#xff0c;通常用于状态管理或表达多种可能的错误类型。 密封类用 sealed 关键字定义&#xff0c;这意味着只能…

Windows系统PyCharm右键运行.sh文件

在参考了Windows系统下pycharm运行.sh文件&#xff0c;执行shell命令_shell在pycharm-CSDN博客 和深度学习&#xff1a;PyCharm中运行Bash脚本_pycharm bash-CSDN博客 配置了右键执行.sh文件之后&#xff0c;发现在Windows的PyCharm中直接右键运行sh文件&#xff0c;存在如下…

Numba: 使用GPUs加速python

作为python函数的即时编译器&#xff0c;Numba是直接在标准python解释器中运行的&#xff0c;所以我们可以直接在GPU上运行用python写的CUDA kernels&#xff08;在显卡上运行的函数&#xff09;&#xff0c;换句话说&#xff0c;Numba可以让我们直接使用python而非学习一门新语…

2-124 基于matlab得结构稀疏字典实现SAR图像低秩重建

基于matlab得结构稀疏字典实现SAR图像低秩重建&#xff0c;通过K-SVD和W-KSVD结合OMP进行重建。K-SVD算法是一种字典学习算法&#xff0c;能够对字典进行优化&#xff0c;使其能够更好地表示训练样本集。W-KSVD算法是K-SVD算法的扩展&#xff0c;它能够利用权重信息对字典进行优…

网络安全的挑战与对策:从技术防御到综合治理的全方位分析

引言 随着互联网的迅猛发展,网络安全已成为全球关注的焦点之一。网络技术的进步为社会带来了巨大的经济、文化和科技红利,但也使得信息系统面临越来越复杂的安全威胁。网络攻击的种类日益多样化、攻击技术日益成熟化,给个人、企业、政府以及关键基础设施带来了严重的安全挑…