Flutter Widget:StatefulWidgetStatelessWidgetState

news2024/12/23 22:24:58

Widget 概念

Widget 将是构建Flutter应用的基石,在Flutter开发中几乎所有的对象都是一个 Widget 。

在Flutter中的widget 不仅表示UI元素,也表示一些功能性的组件,如:手势 、主题Theme 等。而原生开发中的控件通常只是指UI元素。Flutter 中是通过 Widget 嵌套 Widget 的方式来构建UI和进行事件处理的。所以记住,Flutter 中万物皆为Widget

@immutable // 不可变的
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
  final Key? key;//决定是否在下一次build时复用旧的widget 
  @protected
  @factory
  Element createElement();
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
  ...
}
  • 抽象类widget类继承自DiagnosticableTree即“诊断树”;
  • createElement():一个 widget 可以对应一个或多个Element
  • canUpdate():判断newWidgetoldWidgetruntimeTypekey同时相等时就会用new widget去更新Element对象的配置,否则就会创建新的Element 

Flutter的三棵树

Widget 描述一个UI元素的配置信息,渲染由Render完成。FlutterUI框架处理流程如下:

  1. 根据 Widget 树生成一个 Element 树。
  2. 根据 Element 树生成 Render 树(渲染树)。
  3. 根据渲染树生成 Layer 树,然后上屏显示。

Element 是 Widget 和 RenderObject 的粘合剂(中间层)。案例如下所示: 

Container( // 一个容器 widget
  child: Row( // 可以将子widget沿水平方向排列
    children: [
      Image.network('https://www.example.com/1.png'), // 显示图片的 widget
      const Text('A'),// 显示文本的 widget
    ],
  ),
);

Image 内部会通过 RawImage 来渲染图片、Text 内部会通过 RichText 来渲染文本,所以最终的 Widget树、Element 树、渲染树结构如下图所示:

         在上面的三棵树中,Widget 和 Element 是彼此对应的,但它们并不和 RenderObject 对应。比如 StatelessWidget 和 StatefulWidget 都没有对应的 RenderObject。

          在 Flutter 开发中,一般都不直接继承Widget类来实现一个新控件或组件,而是通过继承StatelessWidgetStatefulWidget来间接继承widget类来实现。


StatelessWidget

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

@override
StatelessElement createElement() => StatelessElement(this);

StatelessWidget用于不需要维护状态的场景。

它通常在build方法中通过嵌套其他 widget 来构建UI。例如文本的回显,示例如下:

class ContextRoute extends StatelessWidget  {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Context测试"),
      ),
      body: Container(
        child: Builder(builder: (context) {
          // 在 widget 树中向上查找最近的父级`Scaffold`  widget 
          Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();
          // 直接返回 AppBar的title, 此处实际上是Text("Context测试")
          return (scaffold.appBar as AppBar).title;
        }),
      ),
    );
  }
}

(运行看效果):

其中,build方法有一个context参数,它是BuildContext类的一个实例,表示当前 widget 在 widget 树中的上下文,每一个 widget 都会对应一个 context 对象(因为每一个 widget 都是 widget 树上的一个节点) 。


StatefulWidget

StatefulWidget 可以拥有状态,这些状态在 widget 生命周期中是可变的,而 StatelessWidget 是不可变的。

StatelessWidget一样,StatefulWidget也是继承自widget类,并重写了createElement()方法。不同之处如下:

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);   
  @protected
  State createState();//创建state
}

StatefulElement中可能会多次调用createState()来创建状态(State)对象。而在StatefulWidget 中,State 对象和StatefulElement具有一一对应的关系。


State

表示 StatefulWidget 要维护的状态。

一个 StatefulWidget 类可以有一个或多个State实例,而State实例只关联一个widget 实例。

State 中的保存的状态信息可以在 widget 生命周期中被改变。手动调用其setState()会通知Flutter 框架状态发生改变,然后调用其build方法重新构建 widget 树,从而达到更新UI的目的。

State 中有两个常用属性:

  1. widget,它表示与该 State 实例关联的 widget 实例。这种关联并非永久的,State实例只会在第一次插入到树中时被创建,当在重新构建时widget 被修改了,Flutter 框架会动态设置State. widget 为新的 widget 实例。

  2. context。StatefulWidget对应的 BuildContext。


 StatefulWidget生命周期

  • initState:当 widget 第一次插入到 widget 树时会被调用。且Flutter 框架只会调用一次该回调。通常在该回调中做一些一次性的操作,如状态初始化、订阅子树的事件通知等。

  • didChangeDependencies():当State对象的依赖发生变化时会被调用。需要注意,组件第一次被创建和挂载的时候对应的didChangeDependencies会被调用。

  • build():主要是用于构建 widget 子树的。

  • reassemble():此回调是专门为了开发调试而提供的。在热重载(hot reload)时会被调用,此回调在Release模式下永远不会被调用。

  • didUpdateWidget ():在 widget 重新构建时(复用)调用此回调。

  • deactivate():当 State 对象从树中被移除时,会调用此回调。如果移除后没有重新插入到树中则紧接着会调用dispose()方法。

  • dispose():当 State 对象从树中被永久移除时调用;通常在此回调中释放资源。


本篇介绍了Widget的相关概念,了解到在Flutter开发中几乎所有的对象都是一个 Widget 。

下一篇,以一个简单应用示例,使用Widget构建一个Flutter页面。

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

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

相关文章

[Rust] 使用vscode实现HelloWorld程序并进行debug

一、简介 本文介绍了如何使用vscode编写rust&#xff0c;实现打印"Hello, world!"的程序。 二、工具安装 0. 环境介绍&#xff1a; Linux &#xff08;或者windowswsl&#xff09; 1. 安装rust编译器rustc和包管理器cargo。 请参考连接&#xff1a;Rust 程序设…

Skywalking的Helm Chart方式部署

背景 之前介绍了AWS云上面的EKS的集中日志方案。这次主要介绍调用链监控了&#xff0c;这里我们用的是Skywalking。监控三王者&#xff08;EFKPrometheusSkywalking&#xff09;之一。之前AWS云上面使用fluent bit替代EFK方案&#xff0c;其实&#xff0c;AWS云在调用链方面&a…

1Panel应用推荐:DataEase开源数据可视化分析工具

1Panel&#xff08;github.com/1Panel-dev/1Panel&#xff09;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;它致力于通过开源的方式&#xff0c;帮助用户简化建站与运维管理流程。为了方便广大用户快捷安装部署相关软件应用&#xff0c;1Panel特别开通应用商店&am…

查看Scala类的方法

文章目录 一、概述如何查看Scala类的方法二、使用Scala文档查看类的方法三、使用反射机制查看类的方法 一、概述如何查看Scala类的方法 本文介绍了在Scala中查看Int类方法的两种方法&#xff1a;使用Scala标准库文档和使用反射机制。通过Scala标准库文档&#xff0c;您可以方便…

Qt 项目使用visual studio 进行开发调试

https://marketplace.visualstudio.com/items?itemNameTheQtCompany.QtVisualStudioTools2015 https://devblogs.microsoft.com/cppblog/bring-your-existing-qt-projects-to-visual-studio/ 正常Qt开发中&#xff0c;使用Qt Creator 进行windows下MSVC编译器的调试是一件挺麻…

jenkins构建完成后部署到本机,无法读取容器外文件夹

项目背景&#xff1a; Dockerjenkins 构建完成后&#xff0c;要把打包的dist文件夹内容移动到网站目录 /www/wwwroot/xxxxxx 文件夹下&#xff1b;但是获取不到jenkins容器外的文件夹。 解决办法&#xff1a; 在容器中&#xff0c;添加挂载/映射本机目录&#xff0c;把网站…

【C语言_数组_复习篇】

目录 一、数组的概念 二、数组的类型 三、一维数组 3.1 一维数组的创建 3.2 一维数组的初始化 3.3 一维数组的访问 3.4 一维数组在内存中的存储 四、二维数组 4.1 二维数组的创建 4.2 二维数组的初始化 4.3 二维数组的访问 4.4 二维数组在内存中的存储 五、变长数组 六、…

大数据主要组件HDFS Iceberg Hadoop spark介绍

HDFSIceberghadoopspark HDFS 面向PB级数据存储的分布式文件系统&#xff0c;可以存储任意类型与格式的数据文件&#xff0c;包括结构化的数据以及非结构化的数据。HDFS将导入的大数据文件切割成小数据块&#xff0c;均匀分布到服务器集群中的各个节点&#xff0c;并且每个数据…

R语言:vagen包做微生物香农指数分析,ggplot2画箱线图

> setwd("目录路径") > library(vegan) > library(picante) > library(openxlsx) > library(ggplot2) > library(ggsci) > otu <- read.xlsx("OTU.xlsx",rowNames T) > head(otu)T1 T2 T3 T5 T6 T8 T9 N…

瑞_23种设计模式_状态模式

文章目录 1 状态模式&#xff08;State Pattern&#xff09;1.1 介绍1.2 概述1.3 状态模式的结构1.4 状态模式的优缺点1.5 状态模式的使用场景 2 案例一2.1 需求2.2 代码实现&#xff08;未使用状态模式&#xff09;2.3 代码实现&#xff08;状态模式&#xff09; 3 案例二3.1 …

基于python+vue网络相册设计与实现flask-django-nodejs-php

网络相册设计与实现的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&#xff0…

递归的个人总结

递归函数&#xff08;递去、回归&#xff09;是函数不断的调用自己&#xff1b; 可以按照如下来理解&#xff1a;func1中调用func2&#xff0c;func2中调用func3; func3函数返回了&#xff0c;继续执行func2中的语句&#xff1b;func2执行完了&#xff0c;继续执行func1之后的…

备考ICA----Istio实验6---流量镜像 Traffic Mirroring 实验

备考ICA----Istio实验6—流量镜像 Traffic Mirroring 实验 流量镜像功能可以将生产的流量镜像拷贝到测试集群或者新的测试版本中&#xff0c;在不影响实际生产环境的情况下&#xff0c;测试具有实际生产流量的服务&#xff0c;帮助减低版本变更的风险。也可以用在不同集群间的…

定制 Elasticsearch 镜像

安装ik分词器 下载ik分词器 下载地址&#xff1a;https://github.com/infinilabs/analysis-ik/releases Dockerfile FROM docker.elastic.co/elasticsearch/elasticsearch:8.12.2 COPY ./elasticsearch-analysis-ik-8.12.2.zip /opt/ RUN bin/elasticsearch-plugin instal…

如何在 Odoo 17 的 齿轮菜单⚙️ 中添加新菜单

在 Odoo 中&#xff0c;齿轮菜单是一个重要组件&#xff0c;允许用户访问与系统内不同模型和功能相关的各种配置选项和设置。它通常由位于用户界面左上角的齿轮或齿轮图标表示。下图显示了 "sale.order "模型的齿轮菜单。 默认情况下&#xff0c;我们在 CogMenu 中提…

当我想用ChatGPT-Next-Web来套壳Azure OpenAI Service时

使用Cloudflare worker来代理Azure OpenAI API&#xff0c; 并将其转换为兼容OpenAI的API 一直没能搞定OpenAI的订阅&#xff0c; 就因为没有搞定国外的信用卡&#xff0c; 所以就一直使用GPT-3.5来处理日常的文字生成工作&#xff0c; 例如写文档&#xff0c; 生成一些简单的脚…

前言:为什么C语言最适合编程入门?

前言&#xff1a;为什么C语言最适合编程入门&#xff1f; C语言被认为最适合编程入门的原因主要有以下几点&#xff1a; 基础且强大&#xff1a;C语言是一种基础且强大的编程语言。它提供了对底层硬件的直接访问&#xff0c;让初学者能够更好地理解计算机的工作原理&#xff0…

使用jupyter-Python进行模拟股票分析

tushare财经数据接口包 pip install tushare作用&#xff1a;提供相关指定的财经数据 需求&#xff1a;股票分析 使用tushare包获取某股票的历史行情数据 输出该股票所有收盘比开盘上涨3%以上的日期 输出该股票所有开盘比前日收盘跌幅超过2%的日期 假如我从2015年1月1日开…

二、阅读器的开发(初始)-- 2、阅读器开发

1、epubjs核心工作原理 1.1 epubjs的核心工作原理解析 epub电子书&#xff0c;会通过epubjs去实例化一个Book对象&#xff0c;Book对象会对电子书进行解析。Book对象可以通过renderTo方法去生成一个Rendition对象&#xff0c;Rendition主要负责电子书的渲染&#xff0c;通过R…

蓝桥杯第二天刷真题

public class Main {public static void main(String [] args) { //存大数方法String s"202320232023"; // 定义一个字符串&#xff0c;它将被转换为结束循环的数值long end Long.parseLong(s);long sum 0;long primarynumber 1;for(int i 1; i<end; i) {long …