1-简介
是Flutter上的一个轻量且强大的解决方案,提供了很多精密组件、路由管理、高性能的状态管理、依赖注入(多个组件,页面之间共享数据)和主题管理等。
初步体验:点击按钮,页面的数字累加
import 'package:flutter/material.dart';
import 'package:get/get.dart';
main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatelessWidget {
var times = 0.obs;//obs意思:让数据变成可被刷新的数据
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是一个标题'),
),
body: Center(
child: Obx(() => Text(
/*
Obx():这是一个Widget,表示观察可观察对象并自动刷新UI。
在括号中,我们可以传递一个函数来构建UI组件,通常使用lambda表达式() =>来定义。
这个函数会在可观察对象发生变化时自动调用,并返回一个新的UI组件。
*/
times.value.toString(),// 获取times的值并转换为字符串显示。
//注意:times的数据类型是RxInt,需要用times.value获取times的值
//为了简化开发人员的操作,在GetX库中允许times.toString()获取值
style: TextStyle(fontSize: 50),
),)
),
floatingActionButton: FloatingActionButton(
onPressed: () {times++;},
child: Icon(Icons.add),
),
);
}
}
真的很方便很简洁。
2-组件
GetX提供了很多美观使用的组件,可以通过函数触发的形式来调出。
2-1SnackBar
main.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/views/home.dart';
main() {
runApp(GetMaterialApp(
home: Home(),
));
}
/*
通过调用runApp函数启动Flutter应用程序,并将GetMaterialApp作为根组件。
GetMaterialApp是GetX库提供的特殊组件,它包含了一些常用的功能,例如状态管理、路由管理等
*/
home.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是首页'),
),
body: Center(
child: Text("这里是首页的内容"),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Get.snackbar('点击首页上的按钮后弹出的标题', '点击首页上的按钮后弹出的内容');
//使用了GetX库提供的Get.snackbar()方法来创建一个弹出通知框,用于演示GetX库中的弹出消息组件
},
child: Icon(Icons.add),
),
);
}
}
更改弹出通知框的样式
onPressed: () {
Get.snackbar('title', 'message',
titleText: Text('这是弹出通知框的标题',style: TextStyle(color: Colors.red,fontSize: 30),),
messageText: Text('这是弹出通知框的内容',style: TextStyle(color: Colors.blue,fontSize: 20),),
snackPosition: SnackPosition.BOTTOM,//从哪个位置出现弹窗
duration: Duration(milliseconds: 5000)//显示多少毫秒
);
//使用了GetX库提供的Get.snackbar()方法来创建一个弹出通知框,用于演示GetX库中的弹出消息组件
},
2-2DefaultDialog
使用DefaultDialog默认会从中间弹出一个信息框,点击周围暗淡的区域即可退出。
home.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是首页'),
),
body: Center(
child: Text("这里是首页的内容"),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Get.defaultDialog(
title: '提示',
content: Text('你已经被踢出群聊'),
confirm: TextButton(
onPressed: (){
Get.back();//退出信息框
Get.snackbar('确认成功', '你已经退出该群');//点击【确认】按钮后执行
},
child: Text('确认')
),
barrierDismissible: false//禁止点击暗淡区域退出信息框
);
},
child: Icon(Icons.add),
),
);
}
}
2-3BottomShet
调用该组件将从底部弹出一个窗口,使用它时,需要设定其高度(默认高度为0)和颜色(默认透明色,默认看不到,但是确实存在)。
home.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是首页'),
),
body: Center(
child: Text("这里是首页的内容"),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Get.bottomSheet(
Container(
color: Colors.white,
height: 200,
child: Center(child: ElevatedButton(
onPressed: (){Get.back();},
child: Text('退出bottomSheet'),
)),
),
isDismissible: false,//禁止点击阴影部分关闭底部窗口
enableDrag: false,//禁止采用拖拽的方式关闭底部窗口
);
},
child: Icon(Icons.add),
),
);
}
}
3-主题管理
home.dart文件代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是首页'),
),
body: Center(
child: Text("这里是首页的内容"),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Get.changeTheme(
Get.isDarkMode?ThemeData.light():ThemeData.dark()//通过三元运算符判断是否是夜间模式(点击按钮完成夜间模式和日间模式的切换)
);
},
child: Icon(Icons.add),
),
);
}
}
4-路由
GetX总共提供了两种跳转方式,一种是普通路由跳转,一种是命名路由跳转。使用GetX的路由功能也需要将main.dart中的MateralApp变为GetMateralApp。
4-1普通路由
对于普通路由的使用,我们一般使用Get.to,Get.back,Get.off,Get.offAll,适用如下:
Get.to:
需要传入一个跳转的目标,在home.dart中,通过设置按钮点击事件调用Get.to来跳转到Page2
home.dart文件代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/page2.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是首页'),
),
body: Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Text('这是首页'),
ElevatedButton(
onPressed: () {
Get.to(Page2());//会留下路由跳转记录的跳转方式
// Get.off(Page2());进入下一个页面后,在下一个页面无法返回本页面
},
child: Text('跳去page2页面'),
),
])),
);
}
}
page2文件代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/page3.dart';
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是page2页面'),
),
body: Center(
child: Column(
children: [
ElevatedButton(
child: const Text('跳去page3页面'),
onPressed: () {
Get.to(page3());
},
),
ElevatedButton(
child: const Text('返回上一页'),
onPressed: () {
Get.back();
},
)
],
),
));
}
}
page3文件代码:
import 'package:flutter/material.dart';
import 'package:flutter_demo_1/views/home.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/page3.dart';
class page3 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是page3页面'),
),
body: Center(
child: Column(
children: [
ElevatedButton(
child: const Text('返回上一页'),
onPressed: () {
Get.back();
},
),
ElevatedButton(
child: const Text('返回home主页'),
onPressed: () {
Get.offAll(Home());//会删除所有的路由跳转记录,Home页面左上角不会出现返回箭头
},
)
],
),
));
}
}
4-2路由跳转动画
第一种方式transition:
从一个页面跳转到第二个页面涉及到一些跳转动画,转场效果需要通过transition参数传入,使用duration来传入时间
Get.to(Page2(),transition: Transition.zoom,duration: Duration(seconds: 2));
第二种方式curve:
Get.to(Page2(),curve: Curves.easeInBack,duration: Duration(seconds: 2));
定义全局的转场效果
main.dart文件中
main() {
runApp(GetMaterialApp(
defaultTransition: Transition.upToDown,
home: Home(),
));
}
4-3普通路由传值
普通路由传值的方式只有一种,使用arguments参数进行传入
home.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/page2.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是首页'),
),
body: Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Text('这是首页'),
ElevatedButton(
onPressed: () {
Get.to(Page2(),arguments: {'name':'小明','age':10});
},
child: Text('跳去page2页面'),
),
])),
);
}
}
page2.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/page3.dart';
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这里是page2页面'),
),
body: Center(
child: Column(
children: [
Text(Get.arguments['name']+Get.arguments['age'].toString()),//Get.arguments代表了MAP,也就是home.dart里的{'name':'小明','age':10}
ElevatedButton(
child: const Text('跳去page3页面'),
onPressed: () {
Get.to(page3());
},
),
ElevatedButton(
child: const Text('返回上一页'),
onPressed: () {
Get.back();
},
)
],
),
));
}
}
4-4命名路由
通过提前给每一个页面进行命名后使用的路由模式。
简单使用:
对main.dart进行修改:
import 'package:flutter/material.dart';
import 'package:flutter_demo_1/page2.dart';
import 'package:flutter_demo_1/page3.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/views/home.dart';
main() {
runApp(GetMaterialApp(
initialRoute: 'p3',//手动锁定APP打开后显示的界面
getPages: [
GetPage(name: '/', page: ()=>Home()),//name: '/'代表首页的标志,也就是首页对应的字符串
GetPage(name: '/p2', page: ()=>Page2()),//name: '/p2'代表page2页面
GetPage(name: '/p3', page: ()=>page3())//name: '/p3'代表page3页面
],
));
}
home.dart文件里的代码:
ElevatedButton(
onPressed: () {
Get.toNamed('/p2',arguments: {'name':'小明','age':10});
},
child: Text('跳去page2页面'),
),
通常情况下,我们需要保证入口文件的简洁,所以,我们需要把这些代码放在别的文件中。
在lib文件夹下新建文件夹route,在route文件夹下新建文件my_route.dart
my_route.dart文件中的代码:
import '../views/home.dart';
import 'package:flutter/material.dart';
import 'package:flutter_demo_1/page2.dart';
import 'package:flutter_demo_1/page3.dart';
import 'package:get/get.dart';
class MyRouter{
var pages = [
GetPage(name: '/', page: ()=>Home()),//name: '/'代表首页的标志,也就是首页对应的字符串
GetPage(name: '/p2', page: ()=>Page2()),//name: '/p2'代表page2页面
GetPage(name: '/p3', page: ()=>page3())//name: '/p3'代表page3页面
];
}
main.dart文件中的代码:
import 'package:flutter/material.dart';
import 'package:flutter_demo_1/page2.dart';
import 'package:flutter_demo_1/page3.dart';
import 'package:flutter_demo_1/route/my_route.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/views/home.dart';
main() {
runApp(GetMaterialApp(
initialRoute: 'p3',//手动锁定APP打开后显示的界面
getPages: MyRouter().pages,
));
}
照样可以实现原先的效果。
4-5命名路由跳转动画和传值
动画跳转
可以在my_route.dart内更改
也可以在main.dart中定义全局的转场
传值
可以采用原先的传值方式和接收方式
也可以采用?name=小明&age=18方式和Get.parameters['']接收方式
4-6-中间件
当发生路由跳转时调用,可用于检查是否满足能够跳转的条件(如是否登录)。类似的,路由中间件也经常被抽离出来单独作为一个文件。
首先,在lib文件夹里新建middleware文件夹,在middleware文件夹里新建m1.dart文件。
m1.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class M1 extends GetMiddleware {
@override
RouteSettings? redirect(String? route) {
print("中间件被调用了,这是来自中间件的信息");
return null;
};
}
如果跳转到p2页面,都会先经过中间件,再来决定是否跳到p1页面
my_route.dart文件里的代码:
var pages = [
GetPage(name: '/', page: ()=>Home()),//name: '/'代表首页的标志,也就是首页对应的字符串
GetPage(name: '/p2', page: ()=>Page2(),middlewares: [
M1(),
]),//可以传入多个中间件
GetPage(name: '/p3', page: ()=>page3())//name: '/p3'代表page3页面
]
中间件的作用(中间件的逻辑)
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class M1 extends GetMiddleware {
@override
RouteSettings? redirect(String? route) {
//例子:可以在中间件里判断进入登录页面还是进入首页
print("中间件被调用了,这是来自中间件的信息");
var is_logged = false;//没有登录
void checkLogged(){
//判断数据库里是否有登录信息等一系列操作,
//有登录信息
is_logged = true;
}
if(is_logged){
return RouteSettings(name:'/p2');//登陆成功进入p2页面
}else{
return null;
}
}
}
5-状态管理
状态管理指的就是让数据被多组件可共享的行为。
getx为我们提供了两种状态管理器,一种是响应式状态管理(被动方式,如Obx和GetX),一个是简单状态管理(主动方式GetBuilder)。
5-1响应式状态管理器Obx
在lib文件夹下新建controller文件夹,在controller文件夹下新建c1.dart文件。
c1.dart文件里的代码:
import 'package:get/get.dart';
//定义了一个名为 C1 的类,继承自 GetxController,这个类是 GetX 中的控制器类,用于管理状态和业务逻辑
class C1 extends GetxController{
var times = 0.obs;
//var times = Rx<int>(0);这样写也可以
void increase(){
times++;
}
}
home.dart里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/controller/c1.dart';
class Home extends StatelessWidget {
var c1 = Get.put(C1());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是一个标题'),
),
body: Center(
child: Obx(() => Text(
c1.times.value.toString(),// 获取times的值并转换为字符串显示。
style: TextStyle(fontSize: 50),
),)
),
floatingActionButton: FloatingActionButton(
onPressed: () {c1.increase();},
child: Icon(Icons.add),
),
);
}
}
5-2自定义的类使用响应式变量使用
首先在lib文件夹下新建一个名为entity的文件夹,在里面放咱们的实体类文件,在该文件夹下创建一个名为user.dart的文件并写入如下:
class User{
var name;
User(this.name);
}
c1.dart文件的代码:
import 'package:get/get.dart';
import 'package:flutter_demo_1/entity/user.dart';
class C1 extends GetxController{
var times = 0.obs;
//var times = Rx<int>(0);这样写也可以
void increase(){
times++;
}
//changeName 方法用于修改 u1 对象中的名字
var u1 = User('小明').obs;//响应式变量
void changeName(){
//在方法内部,调用了 update 方法,并传入一个回调函数,用于更新 u1 变量。
u1.update((u1) { u1?.name = '小刚'; });
}
}
home.dart文件里的代码:(点击home页面的按钮,home页面显示的名字改变)
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/controller/c1.dart';
class Home extends StatelessWidget {
var c1 = Get.put(C1());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是一个标题'),
),
body: Center(
child: Obx(() => Text(
c1.u1.value.name,
style: TextStyle(fontSize: 50),
),)
),
floatingActionButton: FloatingActionButton(
onPressed: () {c1.changeName();},
child: Icon(Icons.add),
),
);
}
}
另一种写法:
user.dart里面的代码:
import 'package:get/get.dart';
class User{
var name=''.obs;
User(this.name);
}
c1.dart里面的代码:
import 'package:get/get.dart';
import 'package:flutter_demo_1/entity/user.dart';
class C1 extends GetxController{
var times = 0.obs;
//var times = Rx<int>(0);这样写也可以
void increase(){
times++;
}
var u1 = User('小明'.obs);//响应式变量
void changeName(){
u1.name.value = '小刚';
}
}
home.dart里面的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/controller/c1.dart';
class Home extends StatelessWidget {
//通过 Get.put() 方法将这个新创建的 C1 实例注册到 GetX 的依赖注入系统中,使得我们可以通过 Get.find<C1>() 或 Get.put<C1>(C1()) 等方法来获取或注册 C1 实例。
var c1 = Get.put(C1());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是一个标题'),
),
body: Center(
child: Obx(() => Text(
c1.u1.name.value,
style: TextStyle(fontSize: 50),
),)
),
floatingActionButton: FloatingActionButton(
onPressed: () {c1.changeName();},
child: Icon(Icons.add),
),
);
}
}
列表如何变成一个显示变量并且显示
c1.dart里面的代码:
import 'package:get/get.dart';
import 'package:flutter_demo_1/entity/user.dart';
class C1 extends GetxController{
var times = 0.obs;
//var times = Rx<int>(0);这样写也可以
void increase(){
times++;
}
var u1 = User('小明'.obs);//响应式变量
void changeName(){
u1.name.value = '小刚';
}
var list1 = [1,2,3].obs;
void add(){
list1.add(4);
}
}
home.dart里面的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/controller/c1.dart';
class Home extends StatelessWidget {
var c1 = Get.put(C1());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是一个标题'),
),
body: Center(
child: Obx(() => Text(
c1.list1.length.toString(),
style: TextStyle(fontSize: 50),
),)
),
floatingActionButton: FloatingActionButton(
onPressed: () {c1.add();},
child: Icon(Icons.add),
),
);
}
}
5-3响应式状态管理器GetX
使用方法基本上和Obx一样,明显不同的地方就在于,Obx使用controller只需要在类中获取一次,但是GetX的形式就需要多次取出,都是只需要将组件进行包裹即可,我们来对比一下:
Obx包裹:
Obx(() => Text(
c1.list1.length.toString(),
style: TextStyle(fontSize: 50),
),)
GetX包裹:
//使用 GetX 的 GetX Widget 监听的是 C1 控制器的状态变化,并根据状态变化来更新界面。
GetX<C1>(builder: (C1)=>text(c1.list1.length.toString(),style:TextStyle(fontSize: 30)),)
//在 builder 回调函数中,通过 (C1) 参数获取到了 C1 控制器的实例,然后可以使用该实例来访问其中定义的成员变量和方法
//整个 GetX<C1> 部分的作用是将这个文本与 C1 控制器的状态绑定在一起,当 C1 控制器中的状态发生变化时,文本内容会自动更新。
这两种方法达到的效果一致。
5-4简单的状态管理
简单的控制器虽然使用上没有响应式控制器好用,但是从原理上简单的控制器是通过通知的形式去让监听数据的区域进行更新,而响应式控制器的实现是基于流(每时每刻都在监听控件,一但属性改变,就刷新)的,因此性能并没有简单的状态管理好。基本使用如下:
c1.dart文件里的代码:
import 'package:get/get.dart';
class C1 extends GetxController{
var times = 0;
//var times = Rx<int>(0);这样写也可以
void increase(){
times++;
update();//通知
}
}
home.dart文件里的代码:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_demo_1/controller/c1.dart';
class Home extends StatelessWidget {
var c1 = Get.put(C1());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是一个标题'),
),
body: Center(
child: GetBuilder<C1>(builder: (_)=>Text(
_.times.toString(),
style: TextStyle(fontSize: 50),
),)
),
floatingActionButton: FloatingActionButton(
onPressed: () {c1.increase();},
child: Icon(Icons.add),
),
);
}
}
6-依赖管理
依赖管理实际上指的就是controller的管理,通过对依赖的管理可以实现多个页面之间共享一套数据。