pubspec.yaml 文件:
1`dependencies:
2 get:`
1. 状态管理
状态管理其实就是管理应用的数据,在 get
中也称为控制器,所有的数据都必须放在 继承自 GetController 的类中,才可以在视图中使用
第一步:创建 一个Controller
1`import 'package:get/get.dart';
2
3/// 定义数据控制器
4class HomeController extends GetxController {}`
第二步:在控制器中声明变量
1`/// 定义数据控制器
2class HomeController extends GetxController {
3 // 使用 .obs 作为你值的后缀
4 final name = "老汪".obs;
5
6 // 使用 Rx 和 Darts 泛型,Rx < type >
7 final count = Rx<int>(0);
8
9 // 使用 Rx { Type }
10 final isLogged = RxBool(false);
11}`
第三步:在UI中使用变量
1`import 'package:flutter/material.dart';
2import 'package:getx_demo/page/home_controller.dart';
3
4class HomePage extends StatelessWidget {
5 // 实例化控制器
6 final controller = HomeController();
7
8 @override
9 Widget build(BuildContext context) {
10 return Scaffold(
11 appBar: AppBar(
12 title: Text("状态管理"),
13 centerTitle: true,
14 ),
15 body: Container(
16 width: double.infinity,
17 child: Column(
18 crossAxisAlignment: CrossAxisAlignment.center,
19 children: [
20 Text('name: ${controller.name}'),
21 Text('count: ${controller.count}'),
22 Text('isLogged: ${controller.isLogged}'),
23 Divider(),
24 Text('循环items列表:'),
25 Row(
26 mainAxisAlignment: MainAxisAlignment.center,
27 children:
28 controller.items.map((item) => Text("$item, ")).toList(),
29 )
30 ],
31 ),
32 ),
33 );
34 }
35}`
2. 声明“可观察的”变量
2.1 第一个是使用 Rx { Type }。
1`final name = RxString('');
2final isLogged = RxBool(false);
3final count = RxInt(0);
4final balance = RxDouble(0.0);
5final items = RxList<String>([]);
6final myMap = RxMap<String, int>({});`
2.2 第二种是使用 Rx 和 Darts 泛型,Rx < type >
1`final name = Rx<string>('');
2final isLogged = Rx<bool>(false);
3final count = Rx<int>(0);
4final balance = Rx<double>(0.0);
5final number = Rx<num>(0)
6final items = Rx<List<string>>([]);
7final myMap = Rx<Map<string, int>>({});
8
9// 自定义类
10final user = Rx<User>();`
2.3 第三种方法更实用、更简单也是首选,就是把.obs 作为你的变量的后缀:
1`final name = ''.obs;
2final isLogged = false.obs;
3final count = 0.obs;
4final balance = 0.0.obs;
5final number = 0.obs;
6final items = <String>[].obs;
7final myMap = <String, int>{}.obs;
8
9// Custom classes - it can be any class, literally
10final user = User().obs;`
3. 什么类型可被定义为的obs
你可以在 obs 上转换任何东西:
1`import 'package:get/get.dart';
2
3class User {
4 final name;
5 final age;
6 User({this.name, this.age});
7}
8
9class Teacher {
10 final name = "李思思".obs;
11 final languer = "语文".obs;
12}
13
14/// 定义数据控制器
15class HomeController extends GetxController {
16 // 使用 .obs 作为你值的后缀
17 final name = "老汪".obs;
18
19 // 使用 Rx 和 Darts 泛型,Rx < type >
20 final count = Rx<int>(0);
21
22 // 使用 Rx { Type }
23 final isLogged = RxBool(false);
24
25 // 使用 .obs 作为你值的后缀
26 final items = <String>["flutter", "getx", "redux", "java"].obs;
27
28 // 自定义User类
29 final user = User(name: "Camila", age: 18).obs;
30
31 // 自定义teacher类
32 final teacher = Teacher();
33
34 // Map, 不响应的数据
35 final subjects = {"name": "语文", "desc": "超扫good"};
36}`
37
38
4. 如何改变数据的值
第一步: 计数器案例
1// 创建控制器
2class HomeController extends GetxController {
3 // 使用 Rx 和 Darts 泛型,Rx < type >
4 final count = Rx<int>(0);
5
6 // 每次点击增加1
7 void increment() {
8 print("++")
9 // 必须使用 .value 修饰具体的值
10 this.count.value++;
11 }
12}
第二步: UI中使用,并添加点击事件
1`class HomePage extends StatelessWidget {
2 // 实例化控制器
3 final controller = HomeController();
4
5 @override
6 Widget build(BuildContext context) {
7 return Scaffold(
8 appBar: AppBar(
9 title: Text("状态管理"),
10 centerTitle: true,
11 ),
12 body: Container(
13 width: double.infinity,
14 child: Column(
15 crossAxisAlignment: CrossAxisAlignment.center,
16 children: [
17 Text('数字类型: ${controller.count}'),
18 MaterialButton(
19 onPressed: () {
20 // 直接调用函数
21 controller.increment();
22 },
23 color: Colors.blue,
24 child: Text("change数字类型"),
25 )
26 ],
27 ),
28 ),
29 );
30 }
31}`
32
33
此刻点击,按钮发送事件,控制台会打印数据,数据也确实改变了,但视图不会更新
5. 如何触发视图的更新
在Get中, 有两个不同的状态管理器: 简单的状态管理器(GetBuilder) 和 响应式的管理器(GetX/Obx),所以只有
使用这两个状态管理器修饰的值才会引起视图的更新
5.1 使用GetBuilder()更新
GetBuilder 的目标正是多状态控制。想象一下,你在一个购物车中添加了30种商品,你点击删除一种,同时列表被更新,价格被更新,购物车中的徽章被更新为一个更小的数字。这种类型的方法使得 GetBuilder 成为杀手,因为它将状态分组并同时更改它们,而不需要任何“计算逻辑”。创建 GetBuilder 时就考虑到了这种情况,因为对于状态的临时更改,可以使用 setState,而且不需要状态管理器
这样,如果您想要一个单独的控制器,您可以为它分配 id,或者使用 GetX。这取决于您,记住您拥有的小部件越多,GetX 的性能就越突出,而当状态发生多次更改时,GetBuilder 的性能应该更好。
优点:
只更新所需的小部件。
使用较少内存(接近0mb)的状态管理器
5.1.1 GetBuilder的使用
第一步: 创建控制器
1`/// 定义数据控制器
2class HomeController extends GetxController {
3 // 注意,这里定义普通的值就行,不用使用.obs修饰
4 int count = 0;
5 // 需要手动调用update(),触发更新
6 void increment() {
7 count++;
8 update();
9 }
10}`
第二步:渲染视图并触发更新
1`class HomePage extends StatelessWidget {
2 @override
3 Widget build(BuildContext context) {
4 return Scaffold(
5 appBar: AppBar(
6 title: Text("状态管理"),
7 centerTitle: true,
8 ),
9 body: Container(
10 width: double.infinity,
11 child: Column(
12 crossAxisAlignment: CrossAxisAlignment.center,
13 children: [
14 // 使用GetBuilder, 需要手动调用update()
15 GetBuilder<HomeController>(
16 init: HomeController(),
17 builder: (_) => Column(
18 children: [
19 Text(
20 '数字类型: ${_.count}',
21 style: TextStyle(fontSize: 35),
22 ),
23 MaterialButton(
24 onPressed: _.increment,
25 color: Colors.blue,
26 child: Text("++"),
27 )
28 ],
29 ),
30 ),
31 ],
32 ),
33 ),
34 );
35 }
36}`
5.1.2 如果想用 GetBuilder 具体更新某个具体的小部件,你可以给它们分配唯一的 id:
第一步:添加id属性
1`GetBuilder<HomeController>(
2 id: "num",
3 init: HomeController(),
4 builder: (_) => Column(
5 children: [
6 Text(
7 '数字类型: ${_.count}',
8 style: TextStyle(fontSize: 35),
9 ),
10 MaterialButton(
11 onPressed: _.increment,
12 color: Colors.blue,
13 child: Text("++"),
14 )
15 ],
16 ),
17)`
18
19
第二步:update 时传入某个id属性
1`// 直接按id更新
2void increment() {
3 count++;
4 update(["num"]);
5}
6
7// 您还可以为更新添加条件, 当count 小于 5 时才更新
8void increment() {
9 count++;
10 update(["num"], count < 5);
11}`
5.2 使用Obx()更新
第一步: 创建控制器
1`/// 定义数据控制器
2class HomeController extends GetxController {
3 // 变量必须用final修饰
4 final count = 0.obs;
5 void increment() {
6 count.value++;
7 }
8}`
第二步:渲染UI
1`class HomePage extends StatelessWidget {
2 // 实例化控制器
3 final controller = HomeController();
4
5 @override
6 Widget build(BuildContext context) {
7 return Scaffold(
8 appBar: AppBar(
9 title: Text("状态管理"),
10 centerTitle: true,
11 ),
12 body: Container(
13 width: double.infinity,
14 child: Column(
15 crossAxisAlignment: CrossAxisAlignment.center,
16 children: [
17 // 使用Obx返回渲染的 UI widget
18 Obx(
19 () => Text(
20 '数字: ${controller.count}',
21 style: TextStyle(fontSize: 35),
22 ),
23 ),
24 // 添加点击事件
25 MaterialButton(
26 onPressed: controller.increment,
27 color: Colors.blue,
28 child: Text("++"),
29 )
30 ],
31 ),
32 ),
33 );
34 }
35}`
36
37
在用户界面中,当你想要显示这个值并在值改变时更新屏幕时,只需要这样做:
注1:只有在 定义的变量的值发生变化时才会更改。
如果在一个 Obx 中有5多个 Rx (可观察的)变量,当它们中的任何一个发生变化时,它都会自动更新。
但如果我在一个类中有30个变量,当我更新一个时,它会更新该类中的所有变量吗?
并不会的,只有使用 Rx 变量的特定 Widget 才会更新,因此,当 Rx 变量改变它的值时,GetX 只更新屏幕
5.3 使用 GetX () 更新
用法同GetBuilder(), 但不能添加需要惟一的 id属性,
1`class HomePage extends StatelessWidget {
2 @override
3 Widget build(BuildContext context) {
4 return Scaffold(
5 appBar: AppBar(
6 title: Text("状态管理"),
7 centerTitle: true,
8 ),
9 body: Container(
10 width: double.infinity,
11 child: Column(
12 crossAxisAlignment: CrossAxisAlignment.center,
13 children: [
14 GetX<HomeController>(
15 init: HomeController(),
16 builder: (_) => Column(
17 children: [
18 Text(
19 '数字类型: ${_.count}',
20 style: TextStyle(fontSize: 35),
21 ),
22 MaterialButton(
23 onPressed: _.increment,
24 color: Colors.blue,
25 child: Text("++"),
26 )
27 ],
28 ),
29 ),
30 ],
31 ),
32 ),
33 );
34 }
35}`
6. GetxController生命周期钩子
- onInit : 初次渲染完毕,可以在这里定义控制器(输入框,顶部选项卡,PageView等),调接口
- onClose: 组件卸载时触发,清除定时器等
1`class MyController extends GetxController {
2
3 @override
4 onInit(){
5
6 }
7 @override
8 void onClose() {
9
10 }
11}`
6. 1 演示输入框配合控制器,
- 调接口就不演示了,放到 写 GetConnect 这个文章里
1`// 控制器
2class HomeController extends GetxController {
3 // 用户名控制器
4 TextEditingController userNameController;
5
6 @override
7 void onInit() {
8 super.onInit();
9 userNameController = TextEditingController();
10 print("渲染完成");
11 }
12
13 @override
14 void onClose() {
15 super.onClose();
16 print("close");
17 }
18}
19
20// UI 渲染
21class HomePage extends StatelessWidget {
22 // 实例化控制器
23 final controller = HomeController();
24
25 @override
26 Widget build(BuildContext context) {
27 return Scaffold(
28 appBar: AppBar(
29 title: Text("状态管理"),
30 centerTitle: true,
31 ),
32 body: Container(
33 width: double.infinity,
34 child: Column(
35 crossAxisAlignment: CrossAxisAlignment.center,
36 children: [
37 TextField(
38 controller: controller.userNameController,
39 decoration: InputDecoration(
40 hintText: "请输入用户名",
41 ),
42 onChanged: (val) {
43 print(val);
44 },
45 )
46 ],
47 ),
48 ),
49 );
50 }
51}`
52
53
7. Get.find()
当有多个控制器时,指定使用某个具体的控制器
1`// 现有 - HomeController, LoginController
2Get.find<LoginController>()`
8. 混入状态 StateMixin (保存动态接口数据)
这个一般配合接口数据,在写 getConnect 一块时 说,可以简单看看
另一种处理 UI 状态的方法是使用 StateMixin < t > 。要实现它,可以使用 with 将 StateMixin < t > 添加到允许 t 模型的控制器中
1`class Controller extends GetController with StateMixin<User>{}`
方法可以随时改变状态,只需以下方式传递数据和状态:
1`change(data, status: RxStatus.success());`
允许这些状态:
1`RxStatus.loading();
2RxStatus.success();
3RxStatus.empty();
4RxStatus.error('message');`
要在 UI 中表示它,请使用:
1`class OtherClass extends GetView<Controller> {
2 @override
3 Widget build(BuildContext context) {
4 return Scaffold(
5 body: controller.obx(
6 (state)=>Text(state.name),
7
8 onLoading: CustomLoadingIndicator(),
9 onEmpty: Text('No data found'),
10
11 onError: (error)=>Text(error),
12 ),
13 );
14}`
9. 内置函数工具类 Woker(一般事件发生时触发特定的回调。)
1`/// 变量发出新值时,都会调用
2ever(count1, (_) => print("$_ has been changed"));
3
4/// 在变量第一次被更改时才调用
5once(count1, (_) => print("$_ was changed once"));
6
7/// 防抖,连续点击多次,只执行一次,比如登录,搜索函数中非常有用
8debounce(count1, (_) => print("debouce$_"), time: Duration(seconds: 1));
9
10/// 节流,如果用户在1秒内对一个变量进行了1000次更改,那么他只会在规定的计时器之后发送最后一次更改,默认为800毫秒
11interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1));`
10. 对比 GetBuilder vs GetX vs Obx
GetBuilder 在 内存消耗 方面非常经济,而且几乎没有比他更经济的方法了,但是,GetBuilder 仍然是一个机械状态管理器,您需要手动调用 update () 才会更新视图
GetX 仍然比其他任何反应状态管理器更经济,但是它比 GetBuilder 消耗更多的内存
Obx 比 GetX 更经济,但是输给了 GetBuilder, 与 GetX 和 GetBuilder 不同,您不能在 Obx 中初始化控制器
但使用 Obx,您不需要编写控制器类型,可以从多个不同的控制器中听到更改,但是需要在此之前进行初始化
一劳永逸,使用Obx, 然后是GetX, 追求极致性能使用 GetBuilder