目录
2.更方便的实现SnackBar、Dialog、BottomSheet
前言
这篇文章会从一个简单的工程开始,介绍下GetX的功能。
一、从demo开始体现下Getx的用法
我们先看看getX的路由跳转功能,如下如1所示:
图1.GetX实现路由跳转功能
在图1的过程中,我们实现了路由的跳转,以及路由跳转的时候从堆栈中移除当前页面的功能。
在本篇博客的demo中,还提供了Getx路由跳转的传值功能,以及使用GetX实现SnackBar、Dialog,路由的别名跳转等功能。
图2.路由功能
图3.使用GetX实现Snackbar,Dialog,BottomSheet
二、从最简单的功能开始
写这篇文章的时候,笔者的Flutter版本信息如下:
图4.Flutter本地开发环境
1.新建一个Flutter工程
本来想着一步一步的把创建的过程提出来的,仔细一想,这些基础的代码看到的兄弟们应该都会,这里直接贴出来新建的这个工程吧。
不使用getx版本的实例代码在这里。
您可以下载下来看一下这些功能怎么实现,实在懒或者是感觉代码太简单的haul的话也可以在脑海中思考下这些功能的实现。
下面我们来比较下如何使用Getx实现这些功能。
2.GetX初体验
和其他的Flutter三方库一样,笔者这里用的getx的版本为4.6.6.首先我们应该在yaml文件中配置下getX。
get: ^4.6.6
安装好之后,我们把MaterialApp改成GetMaterialApp即可在项目中使用GetX了。
1.路由跳转
1.普通路由跳转
我们先看一下普通的路由跳转,例如在上面的例子中,普通的路由跳转我们应该这么写:
// 导航到 SecondPage
Navigator.push(context,MaterialPageRoute(builder: (context) => const SecondPage()),);
很长的一段代码,使用get之后,代码如下:
Get.to(()=>const SecondPage());
代码是不是简单了很多,而且不需要获取上下文的context(有些情况下获取context比较麻烦)。
2.跳转并从堆栈中销毁当前页面
我们只需要下面一行代码即可:
Get.off(const ThirdPage());
不使用GetX代码如下:
Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => const ThirdPage()), );
3.跳转并销毁之前所有页面
同样一样代码即可:
Get.offAll(const ThirdPage());
4.跳转以及传值
当我们需要使用路由跳转并传值的时候,我们仅需要再GetMaterialApp中配置getPages属性,代码如下:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state_management/fourth.dart';
import 'package:state_management/second.dart';
import 'package:state_management/third.dart';
import 'home.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),getPages: [
GetPage(name: "/", page: ()=> const MyHomePage()),
GetPage(
name: "/second", page: ()=> const SecondPage(),
transition: Transition.zoom
),
GetPage(name: "/third", page: ()=> const ThirdPage()),
GetPage(name: "/fourth", page: ()=> FourthPage()),
],
home: const MyHomePage(),
);
}
}
当我们需要跳转并传值的时候同样一行代码解决:
Get.toNamed("/fourth",arguments: "Something from second Screen");
在需要接收传值的页面,使用下面的代码也可以一行代码解决:
Get.arguments != null ?Text("上一个页面传递的参数:${Get.arguments}"):const Text(''),
我们还可以在当前页面接收下一个页面的会传值:
ElevatedButton(onPressed: () async { dataFromFourth = await Get.to(FourthPage()); setState(() { }); debugPrint("dataFromFourth:$dataFromFourth"); }, child: const Text('从第四个页面返回数据',style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold),),),
2.更方便的实现SnackBar、Dialog、BottomSheet
使用getx,我们可以在不使用context的情况下使用很少代码实现Snackbar、dialog,BottomSheet。
以SnackBar为例,一行代码搞定Snack:
Get.snackbar("GetX is Awesome", "您应该尝试使用它",snackPosition: SnackPosition.BOTTOM);
不使用getx,代码如下:
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('这是一个 SnackBar!'),
),
);
上述代码的Getx实现示例代码在这里。
三、Getx完整的状态管理功能
上一章节中,我们简单体验了GetX的以便方便之处,这一节我们将详细的讲解下Fluttter的状态管理功能。
1.GetBuilder
这是一种手动状态管理器,内存消耗最小,使用较少的内存(接近0mb),当UI中的单独组件越多,性能越突出。
1.简单的计时器
我们以计数器的效果为例,看一下GetBuilder的用法,在下面的实例中,我们点击count++按钮,计时器每次加1.
图5.计时器实例
我们看看如何实现图5的功能。
首先我们创建一个GetxController用来保存计时器变量,这里要注意的是GetBuilder是手动状态管理器,我们需要主动的调用update方法,代码如下:
import 'package:get/get.dart';
class CounterController extends GetxController{
int counter = 0;
void increment(){
counter++;
update();
}
}
在使用GetBuilder的页面,我们只需要使用GetBuilder包裹住自己的Widget即可。
我们通过Get.put方法获取GetxController实例。
final CounterController counterController = Get.put(CounterController());
当我们点击按钮的时候,直接调用GetxController中的方法即可:
counterController.increment();
完整的一个代码如下:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state_management/controllers/counterController.dart';
class StateManagementPage extends StatelessWidget {
StateManagementPage({super.key});
final CounterController counterController = Get.put(CounterController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.purple,
title: const Text('GetX | StateManagement',style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 16),),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GetBuilder<CounterController>(builder: (_){
return Text("当前Count的值:${_.counter}");},
),
// ElevatedButton(onPressed: (){}, child:Text('count++'',style: TextStyle(color: Colors.bold,))),
const SizedBox(height: 20,),
ElevatedButton(onPressed: (){
counterController.increment();
}, child: const Text('count+1',style: TextStyle(color: Colors.black,))),
const SizedBox(height: 40,),
ElevatedButton(onPressed: (){}, child: const Text('更新姓名和存储数量')),
]
),
),
);
}
}
在上述的代码中,我们首先初始化了一个GetxController实例,然后调用该实例的increment方法,初次之外,我们还可以每次创建GetBuilder的时候,都调用GetxController的初始化方法,代码如下:
GetBuilder<CounterController>(builder: (_){
return Text("当前Count的值:${_.counter}");
},
init: CounterController(),
),
然后我们去ROM中查找GetxController,代码如下:
Get.find<CounterController>().increment();
完整代码如下:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state_management/controllers/counterController.dart';
class StateManagementPage extends StatelessWidget {
StateManagementPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.purple,
title: const Text('GetX | StateManagement',style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 16),),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GetBuilder<CounterController>(builder: (_){
return Text("当前Count的值:${_.counter}");
},
init: CounterController(),
),
// ElevatedButton(onPressed: (){}, child:Text('count++'',style: TextStyle(color: Colors.bold,))),
const SizedBox(height: 20,),
ElevatedButton(onPressed: (){
Get.find<CounterController>().increment();
}, child: const Text('count+1',style: TextStyle(color: Colors.black,))),
const SizedBox(height: 40,),
ElevatedButton(onPressed: (){}, child: const Text('更新姓名和存储数量')),
]
),
),
);
}
}
2.使用GetBuilder的id参数局部更新
GetBuilder提供了一个id参数,用于局部更新界面。通过指定不同的id,可以实现更精细的控件刷新,避免整个页面刷新。
我们以下面的demo为例:点击不同的按钮,更新不同的计数器:
图6.使用GetBuilder参数局部更新
在控制器中使用update指定id:
import 'package:get/get.dart';
class PartialRefreshController extends GetxController{
int counter1 = 0;
int counter2 = 0;void incrementCounter1(){
counter1++;
update(['counter1']); //只更新id为counter1的GetBuilder
update();
}
void incrementCounter2(){
counter2++;
update(['counter2']); //只更新id为counter2的GetBuilder
}}
在页面中使用不同的GetBuilder和id:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:state_management/controllers/partialRefreshController.dart';
class PartialRefreshPage extends StatelessWidget {
const PartialRefreshPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.purple,
title: const Text('GetX | StateManagement',style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold,fontSize: 16),),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 40,),
GetBuilder<PartialRefreshController>(
id: 'counter1',
builder: (controller) => Text('counter1: ${controller.counter1}'),
init: PartialRefreshController(),
),
const SizedBox(height: 40,),
GetBuilder<PartialRefreshController>(
id: 'counter2',
builder: (controller) => Text('counter2: ${controller.counter2}'),
init: PartialRefreshController(),
),
const SizedBox(height: 40,),
ElevatedButton(
onPressed: () {
Get.find<PartialRefreshController>().incrementCounter1();
},
child: const Text('counter1++'),
),
const SizedBox(height: 40,),
ElevatedButton(
onPressed: () {
Get.find<PartialRefreshController>().incrementCounter2();
},
child: const Text('counter2++'),
),
],
)
),
);
}
}
3.使用GetBuilder要注意的点
- GetBuilder用于简单的状态管理,它是一个手动状态管理器,需要我们手动调用update方法更新页面
- 使用GetBuilder的时候,要确保对应的GetxController被初始化
- 使用 id 参数可以实现局部更新,减少不必要的界面重建。
2.Obx
在 Flutter 中,Obx 是 GetX 提供的一种响应式小部件(widget),用于监听和响应数据变化。与 GetBuilder 不同,Obx 使用了 GetX 的响应式变量(Rx 类型),可以自动响应变量的变更并刷新对应的界面,不需要手动调用 update() 方法。Obx 的特点是简单、灵活,特别适合数据频繁变化的场景。
1.简单的计时器
我们还以计时器代码为例:
当我们使用Obx的时候,第一步先定义一个控制器,包含响应式变量counter和增加计数的方法。
import 'package:get/get.dart';
class CounterController extends GetxController {
// 定义一个响应式变量
var counter = 0.obs;
// 增加计数的方法
void increment() {
counter++; // 更新变量,Obx 会自动响应变化
}
}
然后我们就可以在界面中使用Obx。
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'counter_controller.dart'; // 引入控制器
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 初始化控制器
final CounterController counterController = Get.put(CounterController());
return Scaffold(
appBar: AppBar(
title: Text('Obx 示例'),
),
body: Center(
child: Obx(() {
// Obx 会自动监听 counter 变量的变化
return Text(
'点击次数: ${counterController.counter}',
style: TextStyle(fontSize: 24),
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counterController.increment(); // 调用 increment 更新 counter
},
child: Icon(Icons.add),
),
);
}
}
2.多个响应式变量实例
如果控制器中有多个响应式变量,每个变量改变时都会触发 Obx 的重建。
控制器的代码如下:
import 'package:get/get.dart';
class MultiCounterController extends GetxController {
var counter1 = 0.obs;
var counter2 = 0.obs;
void incrementCounter1() {
counter1++;
}
void incrementCounter2() {
counter2++;
}
}
在界面中分别用Obx监听counter1和counter2的变化。
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'multi_counter_controller.dart';
class MultiCounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final MultiCounterController counterController = Get.put(MultiCounterController());
return Scaffold(
appBar: AppBar(title: Text('Obx 多变量示例')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() => Text('计数器1: ${counterController.counter1}', style: TextStyle(fontSize: 24))),
Obx(() => Text('计数器2: ${counterController.counter2}', style: TextStyle(fontSize: 24))),
ElevatedButton(
onPressed: counterController.incrementCounter1,
child: Text('增加计数器1'),
),
ElevatedButton(
onPressed: counterController.incrementCounter2,
child: Text('增加计数器2'),
),
],
),
),
);
}
}
3.总结
-
Obx 非常适合频繁变化的小范围状态管理,自动监听并响应 Rx(响应式)变量的变化。
-
使用 Obx 无需手动调用 update(),代码更简洁。
-
适合响应频繁或实时性较高的场景,比如计数器、表单输入等
3.GetX小组件
在 Flutter 中使用 GetX 包装器可以直接在 UI 中使用 GetX 的响应式管理。你这里的代码使用 GetX 小部件来监听和显示 UserController 中 user 的数据变化。这种方法可以简化代码,将状态更新与 UI 绑定在一起。下面是完整的代码示例,解释如何通过 GetX 实现对用户数据的实时更新。
我们以更新用户名称为例,看一下GetX小组件如何和UI绑定。
1.第一步:创建爱你UserController
import 'package:get/get.dart';
class User {
String name;
User({required this.name});
}
class UserController extends GetxController {
// 创建一个响应式的 user 对象
var user = User(name: 'John Doe').obs;
// 更新用户名称的方法
void updateUser(String newName) {
user.update((val) {
val?.name = newName;
});
}
}
2.第二步:在界面中使用GetX绑定数据
在界面中使用 GetX<UserController> 小部件来监听 user 的变化。每当 user 的 name 属性发生变化时,Text 小部件将自动更新。
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'user_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'GetX Example',
theme: ThemeData(primarySwatch: Colors.blue),
home: UserPage(),
);
}
}
4.GetX其它的一些实用功能
1.设置动画效果
我们可以设置路由跳转时候的一些动画效果,例如缩放效果:
图8.路由跳转缩放效果
一行代码即可实现上述的功能:
Get.to(()=>const OtherPage(),transition: Transition.zoom);
2.国际化
GetX提供了国际化的功能,我们只需要继承Translations,把要国际化的内容以键值对的形式放在字典里即可:
import 'package:get/get.dart';
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {
'hello': 'Hello World',
},
'de_DE': {
'hello': 'Hallo Welt',
}
};
}
使用的时候,只要将.tr
追加到指定的键上,就会使用Get.locale
和Get.fallbackLocale
的当前值进行翻译。
Text('title'.tr);
传递参数给GetMaterialApp
来定义语言和翻译。
return GetMaterialApp(
translations: Messages(), // 你的翻译
locale: Locale('zh', 'CN'), // 将会按照此处指定的语言翻译
fallbackLocale: Locale('en', 'US'), // 添加一个回调语言选项,以备上面指定的语言翻译不存在
);
当我们需要修改语言的时候,调用Get.updateLocale(locale)
来更新语言环境。然后翻译会自动使用新的locale。
var locale = Locale('en', 'US');
Get.updateLocale(locale);
读取系统语言,使用window.locale。
import 'dart:ui' as ui;
return GetMaterialApp(
locale: ui.window.locale,
);