本文旨在记录在学习和使用GetX过程中遇到的问题和心得体会,如果有表达不正确的地方,欢迎下方留言指正😄😄
使用:
首先需要引入包,不赘述了,
其次在入口main.dart里面把MaterialApp
换成GetMaterialApp
return GetMaterialApp(
debugShowCheckedModeBanner: false,
translations: Messages(),
//你的翻译
locale: const Locale('zh', 'CN'),
//按照此处指定的语言翻译
fallbackLocale: const Locale('zh', 'CN'),
//翻译不存在的时候使用次语言
title: 'XXX',
theme: appTheme,
builder: EasyLoading.init(),
initialRoute: routerPage,
defaultTransition: Transition.rightToLeft,
//默认跳转动画
getPages: RouterPage.routes,
);
然后就能在项目中使用了。
首先是一些简单的使用:
弹框
//顶部弹框(toast)
Get.snackbar("Snackbar 标题", "欢迎使用Snackbar");
//弹框
Get.defaultDialog();
//底部弹框
Get. BottomSheet();
路由管理
//路由跳转
Get.to(Home());//通过定义的widget名称来跳转到指定页面
Get.off();//跳转到下个页面,没有返回按钮
Get.offAll();//跳转到下个页面,移除所有的路由
Get.toNamed("/home");//通过路由名称来跳转到指定页面
Get.offNamed("/home");//跳转到下个页面,没有返回按钮
Get.offAllNamed("/home"),//跳转到下个页面,移除所有的路由
//路由跳转传值
Get.toNamed('/home',arguments: {'id':'sdssfsfsf121214'}),
//在下个页面接收传过来的值
Get.arguments['id']
//路由返回到上个页面,并作处理(比如添加数据之后,返回刷新页面)
i:路由跳转的时候,接收返回来的参数value,根据value做判断
Get.toNamed('home')!.then((value) {
if (value) {
//刷新页面
}
});
ii:在路由返回的时候,传参
Get.back(result: true);
Get.to
和Get.toName
的区别:
当使用的binding的时候,如果使用Get.to会报错
The following message was thrown building Builder: "xxxController" not found. You need to call "Get.put(xxxController())" or "Get.lazyPut(()=>xxxController())"
判断是否是手机号、邮箱。。
GetUtils.isEmail('xxx')
GetUtils.isPhoneNumber('xxx')
GetUtils.isDateTime('xxx')
GetUtils.isMD5('xxx')
...
其余API
//给出以前的路由名称
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>()
其次--状态管理:
Getx有两种状态管理:简单状态管理GetBuilder
、响应式状态管理器GetX/Obx
1、在定义变量的时候,加上.obs
var name = 'Jonatas Borges'.obs;
2、在 UI 中,当您想要显示该值并在值更改时更新屏幕时,用Obx包裹控件,如下:
Obx(() => Text("$name"));
3、赋值的时候
name.value = 'Jack';
上面这种我们可以称之为局部刷新
,就是当name的值改变了,只会刷新Text组件,不会刷新整个页面的UI,
使用GetBuilder
是刷新整个页面,适合在列表页面使用
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('maintain_record'.tr)),
body: GetBuilder(
builder: (_) {
return const Padding(
padding: EdgeInsets.all(10.0),
child: Column(
children: [
],
),
);
}
),
);
}
依赖注入-Controller的使用,我感觉能叫他全局状态管理
比如我有两个页面,两个页面都有个Text的组件显示count的值,在两个页面分别修改了count的值,两个页面都会跟着改变,效果如下
可以看到,在两个页面分别操作count的值,两边显示都是一样的
实现:
在class_room_page.dart
中定义一个Text和button
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ClassRoomPage extends StatelessWidget {
const ClassRoomPage({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.put<ClassRoomController>(ClassRoomController());
return Container(
alignment: const Alignment(0, 0),
child: SizedBox(
width: Get.width,
height: 300,
child: Column(
children: [
Obx(() => Text('count的值:${controller.count}')),
TextButton(
onPressed: () {
controller.increment();
},
child: const Text('count +1'),
),
],
),
),
);
}
}
同意在store_page.dart
中
import 'package:firstapp/pages/class_room/class_room_controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class StorePage extends StatelessWidget {
const StorePage({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.find<ClassRoomController>();
return Container(
alignment: const Alignment(0, 0),
child: SizedBox(
width: Get.width,
height: 300,
child: Column(
children: [
Obx(() => Text('count的值:${controller.count}')),
TextButton(
onPressed: () {
controller.decrement();
},
child: const Text('count -1'),
),
],
),
),
);
}
}
然后定一个一个Controller---class_room_controller.dart
import 'package:get/get.dart';
class ClassRoomController extends GetxController {
var count = 0.obs;
void increment() {
count++;
}
void decrement() {
count--;
}
}
里面有两个方法和一个变量,Controller必须要put
一次,然后在别的地方使用的时候用find
,我们一般是使用binding来管理Controller,所以修改一下项目结构,新增一个binding,
all_controller_binding.dart
import 'package:firstapp/pages/class_room/class_room_controller.dart';
import 'package:get/get.dart';
class AllBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<ClassRoomController>(() => ClassRoomController());
}
}
然后再路由中注入binding
GetPage(
name: '/tab',
page: () => const TabBarPage(),
binding: AllBinding(),
),
然后把class_room_page.dart
中final controller = Get.put<ClassRoomController>(ClassRoomController());
换成final controller = Get.find<ClassRoomController>();
但是要注意,在哪个页面使用binding的时候,在路由跳转到这个页面的时候,一定要用Get.toName,
国际化
其中message.dart里面都是对照的翻译
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'zh_CN': {
//登录
'email': '邮箱',
'hint_email': '请输入邮箱',
'hint_email_text': '请输入正确的邮箱',
},
'en_US': {
// Login
'email': 'Email',
'hint_email': 'Please enter your email',
'hint_email_text': 'Please enter the correct email address',
}
};
}
使用的时候,用Text('email'.tr);
用Get实现MVC布局
所有的页面布局都在view中实现,数据处理在Controller里面实现,view继承的是GetView,在布局中不再使用StatefulWidget
如下图:
view里面的代码
class MyView extends GetView<MyController> {
const MyView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('MVC'),
),
body: GetBuilder<MyController>(
builder: (_) {
return ListView.builder(
itemCount: controller.dataList.length,
itemExtent: 50,
itemBuilder: (context, index) {
return ListTile(
title: Text('${controller.dataList[index].name}'),
);
},
);
},
),
);
}
}
Controller里面的代码
class MyController extends GetxController {
final List<ListModel> dataList = <ListModel>[].obs;
@override
void onReady() {
_getData(); //获取数据
super.onReady();
}
Future<void> _getData() async {
String jsonData = await loadJsonData();
Map<String, dynamic> data = json.decode(jsonData);
dataList.clear();
dataList.addAll(
data['data'].map<ListModel>((e) => ListModel.fromJson(e)).toList());
update();
}
}
Future<String> loadJsonData() async {
return await rootBundle.loadString('assets/json/list.json');
}
写了个简单的demo,可以down下来看看,Demo传送门