GetX 是 Flutter的一个框架,主要提供状态管理,依赖注入和路由管理三个方面。整体轻量,响应式的状态管理使用起来特别方便。
1.安装
在pubspec.yaml 文件中引入
dependencies:
get:
在需要的文件中导入头文件:
import 'package:get/get.dart';
入口处配置,需要将MaterialApp
改成 GetMaterialApp
(只有当你要使用路由管理( Get.to()
, Get.back()
等)时才需要这一步。如果你不打算使用它,那么就不需要做第1步)
2.状态管理
Get提供了两种状态管理器,简单的状态管理器和响应式状态管理器。
2.1响应式状态管理
如果想要观察一个变量,你只需要在它的末尾加上".obs",然后将这个变量放在Obx()
这个Widget里面,每当这个变量改变时,才会更新,如果改变的值和原来的value是一样的,这时候界面不会有任何变化。
var count = 0.obs;
Obx(() => Text("Clicks: ${c.count}"));
GetX 提供了三种方法可以把一个变量变成是可观察的。
- 方式一,使用**
Rx{Type}
**
// 建议使用初始值,但不是强制性的
final name = RxString('');
final isLogged = RxBool(false);
final count = RxInt(0);
final balance = RxDouble(0.0);
final items = RxList<String>([]);
final myMap = RxMap<String, int>({});
- 方式二,使用**
Rx
**,规定泛型Rx<Type>
final name = Rx<String>('');
final isLogged = Rx<Bool>(false);
final count = Rx<Int>(0);
final balance = Rx<Double>(0.0);
final number = Rx<Num>(0)
final items = Rx<List<String>>([]);
final myMap = Rx<Map<String, int>>({});
// 自定义类 - 可以是任何类
final user = Rx<User>();
- 方式三,也就是上面介绍的方法,更实用、更简单,只需添加 **
.obs
**,它的.value
就是 初始值
final name = ''.obs;
final isLogged = false.obs;
final count = 0.obs;
final balance = 0.0.obs;
final number = 0.obs;
final items = <String>[].obs;
final myMap = <String, int>{}.obs;
// 自定义类 - 可以是任何类
final user = User().obs;
注意如果要使整个类可观察时,需要用update来更新
// 我们将使整个类成为可观察的,而不是每个属性。
class User{
User({this.name = '', this.age = 0});
String name;
int age;
}
// controller
final user = User().obs;
//当你需要更新user变量时。
user.update( (user) { // 这个参数是你要更新的类本身。
user.name = 'Jonny';
user.age = 18;
});
// 更新user变量的另一种方式。
user(User(name: 'João', age: 35));
// view
Obx(()=> Text("Name ${user.value.name}: Age: ${user.value.age}"));
// 你也可以不使用.value来访问模型值。
user().name; // 注意是user变量,而不是类变量(首字母是小写的)。
2.1简单状态管理
GetBuilder是针对多状态控制的,它将状态分组并一次性改变,而无需为此进行任何 "计算逻辑"。如果需要的是同时改变2、3个widget的状态,或者是短暂的状态变化使用这个相对于响应式编程可以节省大量的内存。
// 创建控制器类并扩展GetxController。
class Controller extends GetxController {
int counter = 0;
void increment() {
counter++;
update(); // 当调用增量时,使用update()来更新用户界面上的计数器变量。
}
}
// 在你的Stateless/Stateful类中,当调用increment时,使用GetBuilder来更新Text。
GetBuilder<Controller>(
init: Controller(), // 首次启动
builder: (_) => Text(
'${_.counter}',
),
)
3.路由管理
GetX路由管理可以免上下文(context),提供了很多简单方便的api,使用前需要将MaterialApp
改成 GetMaterialApp
。
//导航到新的页面。
Get.to(NextScreen());
//关闭页面
Get.back();
//进入下一个页面并删除本页面
Get.off(NextScreen());
//进入下一个界面并取消之前的所有路由
Get.offAll(NextScreen());
//要导航到下一条路由,并在返回后立即接收或更新数据。
var data = await Get.to(Payment());
Get也支持别名路由导航,设置好别名,就可以轻松使用。
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(
name: '/',
page: () => MyHomePage(),
),
GetPage(
name: '/second',
page: () => Other(),
),
//你可以为有参数的路由定义一个不同的页面,也可以为没有参数的路由定义一个不同的页面,但是你必须在不接收参数的路由上使用斜杠"/",就像上面说的那样。
GetPage(
name: '/profile/:user',
page: () => UserProfile(),
),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.cupertino
),
],
)
GetX路由功能还支持类似HTML的动态链接路由,例如:
onPressed: () => Get.toNamed('/second?device=iphone&id=123456')
在对应的second页面打印,就可以获取到我们传递的参数。
print(Get.parameters['device']);
print(Get.parameters['id']);
4.依赖管理
依赖管理就是指管理我们的控制器。它有以下四种实例方法:
4.1 Get.put()
最常见的插入依赖关系的方式,使用put时可以设置的所有选项
Get.put<S>(
// 必备:你想得到保存的类,比如控制器或其他东西。
// 注:"S "意味着它可以是任何类型的类。
S dependency
// 可选:当你想要多个相同类型的类时,可以用这个方法。
// 因为你通常使用Get.find<Controller>()来获取一个类。
// 你需要使用标签来告诉你需要哪个实例。
// 必须是唯一的字符串
String tag,
// 可选:默认情况下,get会在实例不再使用后进行销毁
// (例如:一个已经销毁的视图的Controller)
// 但你可能需要这个实例在整个应用生命周期中保留在那里,就像一个sharedPreferences的实例或其他东西。
//所以你设置这个选项
// 默认值为false
bool permanent = false,
// 可选:允许你在测试中使用一个抽象类后,用另一个抽象类代替它,然后再进行测试。
// 默认为false
bool overrideAbstract = false,
// 可选:允许你使用函数而不是依赖(dependency)本身来创建依赖。
// 这个不常用
InstanceBuilderCallback<S> builder,
)
4.2 Get.lazyPut
懒加载一个依赖,这样它只有在使用时才会被实例化使用,使用lazyPut时可以设置的所有选项
Get.lazyPut<S>(
// 强制性:当你的类第一次被调用时,将被执行的方法。
InstanceBuilderCallback builder,
// 可选:和Get.put()一样,当你想让同一个类有多个不同的实例时,就会用到它。
// 必须是唯一的
String tag,
// 可选:类似于 "永久",
// 不同的是,当不使用时,实例会被丢弃,但当再次需要使用时,Get会重新创建实例,
// 就像 bindings api 中的 "SmartManagement.keepFactory "一样。
// 默认值为false
bool fenix = false
)
4.3 Get.putAsync
可以使用 Get.putAsync
注册一个异步实例,使用putAsync时可以设置的选项
Get.putAsync<S>(
// 必备:一个将被执行的异步方法,用于实例化你的类。
AsyncInstanceBuilderCallback<S> builder,
// 可选:和Get.put()一样,当你想让同一个类有多个不同的实例时,就会用到它。
// 必须是唯一的
String tag,
// 可选:与Get.put()相同,当你需要在整个应用程序中保持该实例的生命时使用。
// 默认值为false
bool permanent = false
)
4.4 Get.create
Get.create()
的目标是创建不共享的实例,但不会被销毁,比如listView中的一个按钮,你想为该列表创建一个唯一的实例--正因为如此,Get.create必须和GetWidget一起使用。
Get.create<S>(
// 需要:一个返回每次调用"Get.find() "都会被新建的类的函数。
// 示例: Get.create<YourClass>(()=>YourClass())
FcBuilderFunc<S> builder,
// 可选:就像Get.put()一样,但当你需要多个同类的实例时,会用到它。
// 当你有一个列表,每个项目都需要自己的控制器时,这很有用。
// 需要是一个唯一的字符串。只要把标签改成名字
String name,
// 可选:就像 Get.put() 一样,
// 它是为了当你需要在整个应用中保活实例的时候
// 区别在于 Get.create 的 permanent默认为true
bool permanent = true
实例化后,可以通过find方法来自动寻找
Controller controller = Get.find();
5.其他
除了这三大功能外,Get还提供了很多其他的功能,比如主题切换,国际化,使用GetConnect通过http或websockets进行前后台通信,还有下面的这些,比如:
// 给出当前页面的args。
Get.arguments
//给出以前的路由名称
Get.previousRoute
// 给出要访问的原始路由,例如,rawRoute.isFirst()
Get.rawRoute
// 允许从GetObserver访问Rounting API。
Get.routing
// 检查 snackbar 是否打开
Get.isSnackbarOpen
// 检查 dialog 是否打开
Get.isDialogOpen
// 检查 bottomsheet 是否打开
Get.isBottomSheetOpen
// 删除一个路由。
Get.removeRoute()
//反复返回,直到表达式返回真。
Get.until()
// 转到下一条路由,并删除所有之前的路由,直到表达式返回true。
Get.offUntil()
// 转到下一个命名的路由,并删除所有之前的路由,直到表达式返回true。
Get.offNamedUntil()
//检查应用程序在哪个平台上运行。
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
//检查设备类型
GetPlatform.isMobile
GetPlatform.isDesktop
//所有平台都是独立支持web的!
//你可以知道你是否在浏览器内运行。
//在Windows、iOS、OSX、Android等系统上。
GetPlatform.isWeb
// 相当于.MediaQuery.of(context).size.height,
//但不可改变。
Get.height
Get.width
// 提供当前上下文。
Get.context
// 在你的代码中的任何地方,在前台提供 snackbar/dialog/bottomsheet 的上下文。
Get.contextOverlay
// 注意:以下方法是对上下文的扩展。
// 因为在你的UI的任何地方都可以访问上下文,你可以在UI代码的任何地方使用它。
// 如果你需要一个可改变的高度/宽度(如桌面或浏览器窗口可以缩放),你将需要使用上下文。
context.width
context.height
// 让您可以定义一半的页面、三分之一的页面等。
// 对响应式应用很有用。
// 参数: dividedBy (double) 可选 - 默认值:1
// 参数: reducedBy (double) 可选 - 默认值:0。
context.heightTransformer()
context.widthTransformer()
/// 类似于 MediaQuery.of(context).size。
context.mediaQuerySize()
/// 类似于 MediaQuery.of(context).padding。
context.mediaQueryPadding()
/// 类似于 MediaQuery.of(context).viewPadding。
context.mediaQueryViewPadding()
/// 类似于 MediaQuery.of(context).viewInsets。
context.mediaQueryViewInsets()
/// 类似于 MediaQuery.of(context).orientation;
context.orientation()
///检查设备是否处于横向模式
context.isLandscape()
///检查设备是否处于纵向模式。
context.isPortrait()
///类似于MediaQuery.of(context).devicePixelRatio。
context.devicePixelRatio()
///类似于MediaQuery.of(context).textScaleFactor。
context.textScaleFactor()
///查询设备最短边。
context.mediaQueryShortestSide()
///如果宽度大于800,则为真。
context.showNavbar()
///如果最短边小于600p,则为真。
context.isPhone()
///如果最短边大于600p,则为真。
context.isSmallTablet()
///如果最短边大于720p,则为真。
context.isLargeTablet()
///如果当前设备是平板电脑,则为真
context.isTablet()
///根据页面大小返回一个值<T>。
///可以给值为:
///watch:如果最短边小于300
///mobile:如果最短边小于600
///tablet:如果最短边(shortestSide)小于1200
///desktop:如果宽度大于1200
context.responsiveValue<T>()
6.总结
从上面可以看出GetX组件功能很强大,而且在Github也非常受欢迎,不过它的路由管理需要使用GetMeterialApp包裹,对应用的侵入性比较强,而且覆盖功能太多,可能会有隐藏的bug,使用起来还是需要注意些。