Flutter 状态管理之GetX库

Flutter 状态管理之GetX

  • 前言
  • 正文
    • 一、创建项目
    • 二、状态组件
    • 三、状态更新UI
    • 四、GetX库
      • ① 添加依赖
      • ② 局部刷新
      • ③ 全局刷新
    • 五、源码

前言

  Flutter使用的是声明式UI,是通过状态去更新UI组件的,因此我们首先就要学习状态的使用。同样为了简化原本的状态使用,我们会使用Getx库。

正文

  之前说要写Flutter,一拖就是一年多,有些不好意思。现在都24年了,终于等到你,下面还是按照我们最属于的思路来吧。

一、创建项目

首先我们创建项目,Flie → New → New Flutter Project...

在这里插入图片描述

然后选择Flutter,这里可以看到Flutter SDK path,已经配置好了,点击Next。

在这里插入图片描述

然后输入工程名为study_state,目前我们只考虑Android和iOS两个平台,因此其他的就不勾选了。

在这里插入图片描述

点击Create按钮,完成项目的创建。

在这里插入图片描述

  创建后我们可以看到main.dart,这里是flutter启动文件,同时我启动了一个模拟器,用的雷电模拟器,至于为什么不用AS自带的模拟器,只能说懂的都懂,不懂的也劝你别去用。

  下面我们首先运行在模拟器上看看,运行到模拟器的时间会比较长,不过运行之后当你再次修改代码之后可以通过热重载直接在模拟器上显示出修改后的内容,快捷键是Ctrl + S,图标是一个黄色的闪电。有时候快捷键不生效则你可以手动的点击这个闪电按钮,如果也不生效就重新安装,总会生效的,做开发就要有一颗平常心。

运行好了,效果如下图所示:

在这里插入图片描述

  当我们点击右下角的浮动按钮之后就会看到屏幕中的数字加1,关于这个里面的内容我在第一篇Flutter文章中就介绍过了,因此下面我们就不过多介绍代码,我们将main.dart中的代码全部清空,如下图所示:

在这里插入图片描述

然后我们再来一步一步的写代码,在这个过程中我们能了解到更多的东西。

二、状态组件

首先我们写一个main函数,代码如下所示:

void main() {}

然后我们在这个当前这个文件中再写一个MyApp类,如下图所示:

在这里插入图片描述

  这里我继承了StatelessWidget,这是一个无状态组件,在你输入之后会有提示,注意一下导包是material.dart中的,推荐你使用这个里面的StatelessWidget,MyApp的代码如下所示:

class MyApp extends StatelessWidget {Widget build(BuildContext context) {// TODO: implement buildthrow UnimplementedError();}
}

  这里重新里面的build()函数,在这里面我们就可以写UI了,但是我们先不写,你可以把MyApp理解为Android的Application,然后我们再写一个HomePage,继承StatefulWidget 这是一个有状态的组件,重写里面的createState(),代码我们也先不改,你可以把HomePage 理解为Activity。

class HomePage extends StatefulWidget {State<StatefulWidget> createState() {// TODO: implement createStatethrow UnimplementedError();}
}

  然后我们再写一个_HomePageState 类,继承自State,这是一个抽象类,支持有状态组件,那么我们传递HomePage进去,代码如下所示:

class _HomePageState extends State<HomePage> {Widget build(BuildContext context) {// TODO: implement buildthrow UnimplementedError();}
}

  这里面的build()函数中我们同样可以设置UI,现在我们就了解了无状态和有状态两种组件,在 Flutter 中,有两种类型的小部件:StatelessWidgetStatefulWidget。它们在功能和使用上有一些区别。

  1. StatelessWidget(无状态小部件):

    • 它是一个不可变的小部件,意味着一旦创建就不能再更改它的状态。
    • 它的属性(props)在创建时被设置,并且在整个生命周期中保持不变。
    • 当父级小部件发生更改时,StatelessWidget 将重新构建,但状态不会发生变化。
    • 由于不需要跟踪状态的改变,StatelessWidget 的构建过程更加高效。
  2. StatefulWidget(有状态小部件):

    • 它是一个可变的小部件,可以在运行时改变其内部状态。
    • 它具有一个持久的状态对象(State),用于存储和跟踪小部件的变化。
    • 当父级小部件发生更改时,StatefulWidget 通过更新关联的状态对象来重新构建。
    • StatefulWidget 通常用于处理需要响应用户交互或动态变化的情况。

在实践中,以下是一些使用场景的示例:

  • 使用 StatelessWidget:当小部件的外观和内容不会随时间而改变时,推荐使用 StatelessWidget,例如静态文本、图标等。
  • 使用 StatefulWidget:当小部件的外观和内容需要根据用户交互、数据变化或其他条件动态更新时,需要使用 StatefulWidget,例如表单、列表视图等。

  需要注意的是,StatefulWidgetState 对象一起工作,后者存储和管理小部件的状态。当使用 StatefulWidget 时,通常需要同时创建一个与之关联的状态类。

  总结起来,StatelessWidget 是一个不可变的小部件,适用于静态内容,而 StatefulWidget 是一个可变的小部件,适用于需要跟踪状态变化的场景。

下面我们将前面所写的代码给串起来,首先是main函数中,修改后代码如下所示:

void main() {return runApp(MyApp());
}

  这里使用了一个runApp()函数,里面传入一个组件即可,无论是什么组件,这里我们传入MyApp(),那么当我们启动之后会运行main函数,然后渲染MyApp()组件,下面我们修改MyApp的代码,如下所示:

class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(title: "Study State",theme: ThemeData(useMaterial3: true),home: HomePage(),);}
}

  这里我们通过构建MaterialApp(),在home属性中添加了HomePage(),那么内容就以HomePage()为主了,再看HomePage ,代码如下所示:

class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() {return _HomePageState();}
}

  这里面的key是一个标识HomePage组件的唯一键,createState()方法在创建HomePage时会被调用。createState()方法返回一个_HomePageState对象,它是HomePage的具体状态类。状态类(State)的主要作用是管理StatefulWidget的状态,并根据需要更新小部件的UI。每当HomePage的状态发生变化时,Flutter会调用_HomePageState类中的build方法来构建最新的UI,下面我们再来看_HomePageState,代码如下所示:

class _HomePageState extends State<HomePage> {Widget build(BuildContext context) {return Scaffold(body: Align(alignment: Alignment.center,child: Container(width: 200,height: 200,alignment: Alignment.center,child: Column(children: [Text("Study State"),ElevatedButton(onPressed: () {print("点击了");}, child: Text("按钮"))],),),),);}
}

  这里首先使用了一个Scaffold(),这是一个页面的构成组件,body属性定义了页面的主要内容区域。在body中,使用Align组件将其子组件在父容器中居中显示。Alignment.center表示子组件在父容器中的居中对齐。

  Align的子组件是一个Container,设置宽度和高度(200x200)。alignment属性设置为Alignment.center,将子组件在自身容器中进行居中对齐。child属性是一个Column组件,这是一个纵向布局组件,里面是一个数组,可以包含多个组件,它包含了两个子小部件:一个Text组件和一个带有文本的ElevatedButton组件。在按钮的点击事件中我们打印一下日志,下面我们重新运行一下。

在这里插入图片描述

点击按钮后,看控制台。

在这里插入图片描述

三、状态更新UI

  下面我们通过状态来更新UI,比如我们将点击按钮将文本内容改成大写,再点击改成小写,下面我们修改_HomePageState类中的代码,如下所示:

class _HomePageState extends State<HomePage> {String test = "study state";bool isUppercase = false;void changeText() {setState(() {isUppercase = !isUppercase;print(isUppercase ? "大写" : "小写");});}Widget build(BuildContext context) {return Scaffold(body: Align(alignment: Alignment.center,child: Container(width: 200,height: 200,alignment: Alignment.center,child: Column(children: [Text(isUppercase ? test.toUpperCase() : test.toLowerCase()),ElevatedButton(onPressed: () {changeText();}, child: const Text("按钮"))],),),),);}
}

  首先我们定义了两个变量,内容和是否大小写,然后写了一个changeText()函数,这个函数中使用了setState(() {}),用于改变状态,在这里面修改了isUppercase 的值,然后Text(isUppercase ? test.toUpperCase() : test.toLowerCase())这行代码,在初始情况下显示为小写,然后我们点击按钮调用changeText()函数,函数中更改isUppercase 的值,通过setState就会刷新UI,此时isUppercase 为true,则Text中显示大写,再点击一下为false就变成小写。这就是状态改变驱动UI。

主要改动地方如下图所示:

在这里插入图片描述

控制台日志如下图所示:

在这里插入图片描述

  通过这种方式当我们有数据改变时就可以更新UI了,只不过刚开始你需要习惯这种方式。声明式UI基本上都是这种方式,了解了Flutter基本的状态更新UI,下面我们再来学习一下GetX这个库。

四、GetX库

  GetX是一个基于Flutter的状态管理和路由导航的解决方案,提供了简单、强大、高性能的工具和功能,以简化Flutter应用程序的开发过程。地址是:GetX,可以去了解一下,下面我们来使用它。

① 添加依赖

在项目的pubspec.yaml文件中,将GetX添加为依赖项:

dependencies:get:

添加位置如下图所示:

在这里插入图片描述

这里后面我并没有写版本号,这表示获取最新的版本,如需获取指定版本,写法如下所示:

dependencies:get: ^4.3.8

然后点击Pub get,获取并安装GetX库,如下图所示:

在这里插入图片描述

  你也可以在Terminal命令行中输入flutter pub get命令,获取并安装GetX库。安装成功后你可以在控制台看到,如下图所示:

在这里插入图片描述

GetX安装成功,同时我们知道最新的版本是4.6.6。

② 局部刷新

  在使用之前我们先将原有的代码分离一下,也就是将Application和Activity分开,在lib下创建一个home文件夹,文件夹下新建一个home_page.dart文件,然后我们将main.dart中的部分代码挪到这里面,代码如下所示:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() {return _HomePageState();}
}class _HomePageState extends State<HomePage> {String test = "study state";bool isUppercase = false;void changeText() {setState(() {isUppercase = !isUppercase;print(isUppercase ? "大写" : "小写");});}Widget build(BuildContext context) {return Scaffold(body: Align(alignment: Alignment.center,child: Container(width: 200,height: 200,alignment: Alignment.center,child: Column(children: [Text(isUppercase ? test.toUpperCase() : test.toLowerCase()),ElevatedButton(onPressed: () {changeText();}, child: const Text("按钮"))],),),),);}
}

然后我们再看main.dart中的代码:

import 'package:flutter/material.dart';import 'home/home_page.dart';void main() {return runApp(MyApp());
}class MyApp extends StatelessWidget {Widget build(BuildContext context) {return MaterialApp(title: "Study State",theme: ThemeData(useMaterial3: true),home: HomePage(),);}
}

  现在我们就进行了分离,下面就可以在home_page.dart中进行GetX的使用了,注意在使用的时候需要导包,在哪里用就在哪里导包,然后编辑器也会提示你导包的。

import 'package:get/get.dart';

修改代码如下所示:

import 'package:flutter/material.dart';
import 'package:get/get.dart';class HomePage extends StatelessWidget {HomePage({super.key});RxString test = "study state".obs;RxBool isUppercase = false.obs;void changeText() {isUppercase.value = !isUppercase.value;if (isUppercase.value) {test.value = test.value.toUpperCase();} else {test.value = test.value.toLowerCase();}print(isUppercase.value ? "大写" : "小写");}Widget build(BuildContext context) {return Scaffold(body: Align(alignment: Alignment.center,child: Container(width: 200,height: 200,alignment: Alignment.center,child: Column(children: [Obx(() => Text(test.value)),ElevatedButton(onPressed: () {changeText();}, child: const Text("按钮"))],),),),);}
}

  这里我们说明一下,在首先使用GetX之后,我将HomePage所继承的组件由StatefulWidget改成了StatelessWidget,然后为变量添加了.obs后缀,使这个变量可观察。然后在changeText()方法中修改可观察变量的值。最后使用Obx包裹需要局部刷新的组件,例如:Obx(() => Text(test.value)),当可观察变量值更新时,Obx包裹中的内容就会进行刷新。

  现在这种模式我们还可以再改一下,将涉及到数据改变的部分剥离出去,让我们的页面只专注于显示和更新即可,在home目录下新建一个home_controller.dart文件,里面的代码如下:

import 'package:get/get.dart';///Home页面控制器
class HomeController extends GetxController {RxString test = "study state".obs;RxBool isUppercase = false.obs;void changeText() {isUppercase.value = !isUppercase.value;if (isUppercase.value) {test.value = test.value.toUpperCase();} else {test.value = test.value.toLowerCase();}print(isUppercase.value ? "大写" : "小写");}
}

  这里就是创建一个HomeController类,继承自GetX的GetxController,注意导包别导错了,然后将changeText()方法挪过来即可,下面我们再会到home_page.dart中,修改代码如下所示:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:study_state/home/home_controller.dart';class HomePage extends StatelessWidget {HomePage({super.key});Widget build(BuildContext context) {final HomeController homeController = Get.put(HomeController());return Scaffold(body: Align(alignment: Alignment.center,child: Container(width: 200,height: 200,alignment: Alignment.center,child: Column(children: [Obx(() => Text(homeController.test.value)),ElevatedButton(onPressed: () {homeController.changeText();}, child: const Text("按钮"))],),),),);}
}

  在build()方法中通过Get.put(HomeController()),得到控制器对象,然后在Text中通过控制器得到里面的值,同样可以调用里面的方法,这样我们就将业务和UI分离了。你现在运行之后效果是和之前一样的,可以试试呢。

③ 全局刷新

  全局刷新我们需要使用到GetBuilder,实际上他就是setState的优化,下面我们改动一下home_controller中的代码,如下所示:

import 'package:get/get.dart';///Home页面控制器
class HomeController extends GetxController {String test = "study state";bool isUppercase = false;String btnText = "大写";void changeText() {isUppercase = !isUppercase;if (isUppercase) {test = test.toUpperCase();btnText = "小写";} else {test = test.toLowerCase();btnText = "大写";}update();}
}

  这里就将.obs后缀去掉了,就不是一个可观察变量了,同时我增加了一个参数,用于显示按钮的文字,在changeText()方法中进行修改,最后调用update()进行全局更新,注意update()方法是结合GetBuilder使用的,下面我们改写home_page中的代码,如下所示:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:study_state/home/home_controller.dart';class HomePage extends StatelessWidget {HomePage({super.key});Widget build(BuildContext context) {return Scaffold(body: GetBuilder<HomeController>(init: HomeController(),builder: (controller) {return Align(alignment: Alignment.center,child: Container(width: 200,height: 200,alignment: Alignment.center,child: Column(children: [Text(controller.test),ElevatedButton(onPressed: controller.changeText,child: Text(controller.btnText))],),),);}),);}
}

  使用GetBuilder包裹构建一个可以全局刷新的组件,在初始化时得到HomeController(),然后在builder中就可以返回一个组件,组件中直接使用controller对象进行参数和方法的使用。

效果图如下所示:

在这里插入图片描述
在这里插入图片描述

五、源码

源码地址:study_state

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

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

相关文章

剖析组件应用市场的安装

java运维管理平台怎么支持组件的安装呢&#xff1f;怎么能够达到和应用市场一样的效果呢&#xff1f;效果图如下&#xff1a; 应用商店支持的组件列表&#xff1a; 应用商店组件的安装&#xff1a; 1.组件包的制作 1.1 组件包结构 package&#xff1a;用于存放实际组件包…

【MySQL进阶】SQL优化

文章目录 SQL 优化主键优化数据组织方式页分裂页合并主键设计原则 insert优化order by优化group by优化limit优化count优化 SQL 优化 主键优化 数据组织方式 在InnoDB存储引擎中&#xff0c;表数据都是根据主键顺序组织存放的&#xff0c;这种存储方式的表称为索引组织表 在In…

数据结构Java版(4)——链表

一、概述 链表是一种常见的数据结构&#xff0c;用于存储一系列具有相同类型的数据元素。它由多个节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。 链表与数组不同&#xff0c;它的节点在内存中不是连续存储的&#xff0c;而是通过每个节点中的指针…

测试C#调用OpenCvSharp和ViewFaceCore从摄像头中识别人脸

学习了基于OpenCvSharp获取摄像头数据&#xff0c;同时学习了基于ViewFaceCore的人脸识别用法&#xff0c;将这两者结合即是从摄像头中识别人脸。本文测试测试C#调用OpenCvSharp和ViewFaceCore从摄像头中识别人脸&#xff0c;并进行人脸红框标记。   新建Winform项目&#xf…

OpenSource - 文件在线预览模块(多格式转 PDF 文件)

文章目录 文件在线预览模块&#xff08;多格式转PDF文件&#xff09;现已支持格式如下界面展示运行方式接口介绍文件上传文件转 PDF文件转图片文件转SVG 参数配置其他说明项目关联关键词文档转换预览技术说明同步转换异步转换 主要技术乱码问题处理帮助文档 前端预览弹出层用法…

整除的特征及解释

整除的特征及解释 整除的含义 简单地说&#xff0c;当一个非零整数除另一个整数得到整数商而没有余数时&#xff0c;叫做整除。如62&#xff1d;3&#xff0c;就说2整除6或6能被2整除。 用数学语言描述&#xff1a;若整数b除以非零整数a&#xff0c;商为整数&#xff0c;且余…

zookeeper弱密码漏洞修复

1.连接zookeeper 进入zookeeper安装目录 bin目录下 ./zkCli.sh -server IP:21812.查看节点 ls /3.查看节点权限 getAcl /zookeeper4.设置IP权限 setAcl / ip:127.0.0.1:cdrwa,ip:10.86.30.11:cdrwazookeeper的权限不具备继承性,父子节点的权限相互独立,因此需要为每个子…

11- OpenCV:自定义线性滤波(卷积,卷积边缘)

目录 一、卷积 1、卷积概念 2、卷积如何工作 3、常见算子&#xff08;卷积核 Kenel&#xff09; 4、自定义卷积模糊 5、代码演示 二、卷积边缘 1、卷积边缘问题 2、处理边缘 3、相关的API说明 4、代码演示 一、卷积 1、卷积概念 &#xff08;1&#xff09;在OpenC…

生成当天递增唯一的流水号的几种方式

说明&#xff1a;当开发中&#xff0c;如交易、文件传输过程中的文件名&#xff0c;可能需要我们使用一串唯一的数字来锁定这一条“交互记录”&#xff0c;即流水号。 本文介绍几种生成6位递增唯一&#xff0c;且每日重置的流水号的方式。 方式一&#xff1a;使用Redis 我们…

SpringSecurity(11)——核心组件和认证流程

获取用户信息 // 获取安全上下文对象&#xff0c;就是那个保存在 ThreadLocal 里面的安全上下文对象 // 总是不为null(如果不存在&#xff0c;则创建一个authentication属性为null的empty安全上下文对象) SecurityContext securityContext SecurityContextHolder.getContext(…

微信轰炸-python实现方法

新手&#xff0c;一般都需要执行以下命令&#xff0c;用来导入对应模块 pip install -i Simple Index pynput 键盘winr进入输入cmd 执行该命令即可&#xff1a;pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pynput 打开pycharm,输入代码如下 from pynput.keybo…

AI视频智能识别技术在智慧农业大棚升级改造管理场景中的应用方案

一、需求分析 随着科技的进步和农业现代化的推进&#xff0c;智能化技术逐渐成为现代农业发展的重要支撑。农业大棚作为现代农业的重要组成部分&#xff0c;其智能化改造对于提高农业生产效率、降低成本、增加收益具有重要意义。利用先进的信息化手段来对农业大棚进行管理&…

NOC总线(2)

1. NoC的路由 在NoC交换信息时&#xff0c;需要确定从源节点到目标节点所经过的路径&#xff0c;这时就需要路由算法来确定该路径。路由算法分为静态路由算法和动态路由算法两种。 静态路由算法对于两节点之间的路径是固定的&#xff0c;结构简单&#xff0c;便于硬件实…

【算法分析与设计】二叉树的层序遍历

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xf…

idea插件开发

1&#xff0c; file-new project 如图&#xff0c;选择了安装路径&#xff0c;报错【select home directory for intellij platform plugin sdk】。&#xff08;注意是安装路径最外层的文件夹&#xff0c;不是里面的lib&#xff0c;jbr这一层级&#xff09; 2&#xff0c;点击了…

HTML前端CSS实现只显示1行或者2行、3行剩余显示省略号

想要做的效果: 文本只一行显示 /**实现思路&#xff1a;1.设置inline-block属相2.强制不换行3.固定高度4.隐藏超出部分5.显示“……”*/ {display: inline-block;white-space: nowrap; width: 100%; overflow: hidden;text-overflow:ellipsis; }文本只多行显示 /** 实现思路&…

【Java发送邮箱】spring boot 发送邮箱

导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dependency> 2.在properties配置邮箱 # 发件人QQ号 spring.mail.username2508575653qq.com # QQ邮箱授权码 sp…

xshell配置隧道转移规则

钢铁知识库&#xff0c;一个学习python爬虫、数据分析的知识库。人生苦短&#xff0c;快用python。 xshell是什么 通俗点说就是一款强大ssh远程软件&#xff0c;可以方便运维人员对服务器进行管理操作&#xff0c;功能很多朋友们自行探索&#xff0c;今天只聊其中一个功能点那…

HNU-数据挖掘-实验2-数据降维与可视化

数据挖掘课程实验实验2 数据降维与可视化 计科210X 甘晴void 202108010XXX 文章目录 数据挖掘课程实验<br>实验2 数据降维与可视化实验背景实验目标实验数据集说明实验参考步骤实验过程1.对数据进行初步降维2.使用无监督数据降维方法&#xff0c;比如PCA&#xff0c;I…

既是API调试平台也是自动化测试工具?Apipost

Apipost提供可视化的API自动化测试功能&#xff0c;使用Apipost研发人员可以设计、调试接口&#xff0c;测试人员可以基于同一数据源进行测试&#xff0c;Apipost 接口自动化功能在上次更新中进行了逻辑调整&#xff0c;带来更好的交互操作、更多的控制器选择&#xff0c;同时新…