一个简单的路由跳转、状态管理
目录
lib/
├── main.dart
├── routes/index.dart // 路由表
├── middlewares/auth_middleware.dart // 登录守卫
├── pages/
│ ├── home_page.dart
│ ├── login_page.dart
│ └── profile_page.dart
└── controllers/auth_controller.dart // 登录状态管理
✅ 1. 登录状态控制器(AuthController)
// controllers/auth_controller.dart
import 'package:get/get.dart';class AuthController extends GetxController {var isLoggedIn = false.obs;void login() => isLoggedIn.value = true;void logout() => isLoggedIn.value = false;
}
✅ 2. 路由守卫中间件(AuthMiddleware)
// middlewares/auth_middleware.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/auth_controller.dart';class AuthMiddleware extends GetMiddleware {@overrideRouteSettings? redirect(String? route) {final auth = Get.find<AuthController>();if (!auth.isLoggedIn.value) {return const RouteSettings(name: '/login');}return null; // 正常访问}@overrideint? priority = 0; // 优先级
}
✅ 3. 页面:Home、Login、Profile
// pages/home_page.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/auth_controller.dart';class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {final auth = Get.find<AuthController>();return Scaffold(appBar: AppBar(title: const Text("首页")),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [const Text("欢迎来到首页"),ElevatedButton(onPressed: () => Get.toNamed("/profile"),child: const Text("进入个人中心"),),ElevatedButton(onPressed: auth.logout,child: const Text("退出登录"),)],),),);}
}
// pages/login_page.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/auth_controller.dart';class LoginPage extends StatelessWidget {@overrideWidget build(BuildContext context) {final auth = Get.find<AuthController>();return Scaffold(appBar: AppBar(title: const Text("登录页")),body: Center(child: ElevatedButton(onPressed: () {auth.login();Get.offAllNamed('/home');},child: const Text("点击登录"),),),);}
}
// pages/profile_page.dart
import 'package:flutter/material.dart';class ProfilePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return const Scaffold(body: Center(child: Text("这是个人中心")),);}
}
✅ 4. 路由定义(routes.dart)
// routes.dart
import 'package:get/get.dart';
import 'middlewares/auth_middleware.dart';
import 'pages/home_page.dart';
import 'pages/login_page.dart';
import 'pages/profile_page.dart';final List<GetPage> appRoutes = [GetPage(name: '/login', page: () => LoginPage()),// 添加守卫的页面GetPage(name: '/home',page: () => HomePage(),middlewares: [AuthMiddleware()],),GetPage(name: '/profile',page: () => ProfilePage(),middlewares: [AuthMiddleware()],),
];
✅ 5. 启动文件(main.dart)
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'controllers/auth_controller.dart';
import 'routes.dart';void main() {Get.put(AuthController()); // 注册控制器runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return GetMaterialApp(debugShowCheckedModeBanner: false,initialRoute: '/home',getPages: appRoutes,);}
}
重点
- Get.find(); 在 main() 中全局注册
- 路由配置中需要添加 中间件
Getx 路由套转配置方式
方法 | 功能 | 示例 |
---|
Get.to() | 普通跳转 | Get.to(DetailPage()) |
Get.toNamed() | 跳转到命名路由 | Get.toNamed('/home') |
Get.back() | 返回上一页 | Get.back() |
Get.off() | 替换当前页面 | Get.off(DetailPage()) |
Get.offNamed() | 替换并跳转命名路由 | Get.offNamed('/home') |
Get.offAll() | 清除所有页面,跳转 | Get.offAll(MainPage()) |
Get.offAllNamed() | 清除所有页面并跳转命名路由 | Get.offAllNamed('/login') |
Get.toNamed('/page', arguments: data) | 传递数据 | 接收:Get.arguments |
Get.toNamed('/page/123') | 传递路径参数 | Get.parameters['id'] |
✅ 二、路由配置:GetMaterialApp + getPages
void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return GetMaterialApp(title: 'GetX Demo',initialRoute: '/',getPages: [GetPage(name: '/', page: () => HomePage()),GetPage(name: '/login', page: () => LoginPage()),GetPage(name: '/detail/:id', page: () => DetailPage()),],);}
}
✅ 三、参数传递方式
传递 arguments(类似 Vue 的 query)
// 跳转时传
Get.toNamed('/detail', arguments: {'title': 'GetX 超棒!'});// 接收
final args = Get.arguments;
2️⃣ 传递 path 参数(像 /user/123)
// 定义路由
GetPage(name: '/user/:id', page: () => UserPage());// 跳转
Get.toNamed('/user/123');// 接收参数
final id = Get.parameters['id']; // 获取的是 '123'
✅ 四、嵌套路由(子路由)
GetPage(name: '/parent',page: () => ParentPage(),children: [GetPage(name: '/child', page: () => ChildPage()),],
);
跳转方式:
Get.toNamed('/parent/child');
✅ 五、使用中间件(路由守卫)
GetPage(name: '/home',page: () => HomePage(),middlewares: [AuthMiddleware()],
);
class AuthMiddleware extends GetMiddleware {@overrideRouteSettings? redirect(String? route) {final auth = Get.find<AuthController>();if (!auth.isLoggedIn.value) {return const RouteSettings(name: '/login');}return null;}
}
✅ 六、转场动画
GetPage(name: '/about',page: () => AboutPage(),transition: Transition.rightToLeft,transitionDuration: const Duration(milliseconds: 300),
);
七、导航栏方式(bottomNavigation + 路由)
- 你也可以结合 GetX + IndexedStack 做底部导航 + 路由组合(需要时我可以提供完整例子)。
✅ 跳转方法速查表:
方法 | 作用 |
---|
Get.to(Widget) | Push 一个页面 |
Get.off(Widget) | 替换当前页面 |
Get.offAll(Widget) | 清除所有页面 |
Get.toNamed('/path') | 跳转命名路由 |
Get.offNamed('/path') | 替换当前为命名路由 |
Get.offAllNamed('/path') | 全部清除并跳转命名 |
Get.back() | 返回上一级 |
Get.arguments | 获取传递的对象 |
Get.parameters | 获取 path 中的参数(如 /user/:id) |
Getx 状态管理
- 响应式变量基础(Rx 类型)
- GetX 控制器结构与绑定
- UI 自动刷新更新机制
- GetStorage 实现永久存储
- 增删改查完整示例
- 完整状态管理架构建议
响应式变量基础(Rx 类型)
类型 | 示例 | 使用说明 |
---|
RxInt | RxInt count = 0.obs; | obs 创建响应式变量 |
RxString | var name = ''.obs; | 自动追踪变化 |
RxList | RxList items = [].obs; | 响应式数组 |
RxMap | RxMap map = {}.obs; | 响应式字典 |
Rx<T> | Rx<User> user = User().obs; | 自定义类型 |
改变值方式:
count.value++;
name.value = '新名称';
items.add('新项');
map['key'] = 'value';
2️⃣ GetX 控制器结构与绑定
class CounterController extends GetxController {var count = 0.obs;void increment() {count.value++;}
}
// main.dart
Get.put(CounterController());
// 页面中局部绑定
final counter = Get.put(CounterController());
3️⃣ UI 自动刷新更新机制
- 方法 1:Obx(最推荐)
Obx(() => Text('计数:${counter.count}'));
- 方法 2:GetX Widget
GetX<CounterController>(builder: (controller) => Text('${controller.count}'),
);
- 方法 3:GetBuilder(非响应式,只手动更新)
GetBuilder<CounterController>(builder: (_) => Text('${_.count}'),
);
GetBuilder 适用于不频繁更新的组件,需要手动调用 update()。
4️⃣ GetStorage 实现永久存储(本地缓存)
步骤 1:引入依赖
dependencies:get_storage: ^2.1.1
步骤 2:初始化
void main() async {await GetStorage.init(); // 必须 await 初始化runApp(MyApp());
}
步骤 3:使用
final box = GetStorage();// 存
box.write('isLoggedIn', true);// 取
bool isLoggedIn = box.read('isLoggedIn') ?? false;// 删
box.remove('isLoggedIn');
5️⃣ 增删改查完整示例(以 RxList 为例)
class TodoController extends GetxController {var todos = <String>[].obs;void add(String task) => todos.add(task);void updateAt(int index, String newValue) => todos[index] = newValue;void delete(int index) => todos.removeAt(index);void clear() => todos.clear();
}
final todoController = Get.find<TodoController>();Obx(() => ListView.builder(itemCount: todoController.todos.length,itemBuilder: (_, i) => ListTile(title: Text(todoController.todos[i]),trailing: IconButton(icon: Icon(Icons.delete),onPressed: () => todoController.delete(i),),),
));
6️⃣ 完整状态管理架构建议
功能 | 推荐方式 |
---|
页面数据共享 | 使用 Get.put() 全局注册控制器 |
子页面控制器 | 用 Get.lazyPut() 按需注册 |
多状态切换 | 用多个 RxBool / RxEnum 控制 |
页面重构 | 控制器 + Obx 封装成组件 |
状态持久化 | GetStorage 存取数据 |
中间件判断状态 | Get.find<Controller>().xxx.value |
✅ 示例:登录状态持久化控制器(完整)
class AuthController extends GetxController {final storage = GetStorage();var isLoggedIn = false.obs;@overridevoid onInit() {super.onInit();isLoggedIn.value = storage.read('isLoggedIn') ?? false;}void login() {isLoggedIn.value = true;storage.write('isLoggedIn', true);}void logout() {isLoggedIn.value = false;storage.remove('isLoggedIn');}
}
状态管理,永久存储 get_storage
- 在pubspec.yaml文件中添加库的依赖:
dependencies:get_storage: ^2.1.1
- 然后运行:
flutter pub get
✅ 2. 初始化(必须)
import 'package:get_storage/get_storage.dart';void main() async {await GetStorage.init(); // 初始化存储runApp(MyApp());
}
注意:await GetStorage.init() 是异步方法,必须在 runApp() 前执行。
✅ 3. 基本用法
final box = GetStorage(); // 实例化,默认使用 'GetStorage' 区域// 写入数据
box.write('username', '张三');// 读取数据
String name = box.read('username') ?? '游客';// 删除某个值
box.remove('username');// 清空所有数据
box.erase();// 判断是否存在
bool exists = box.hasData('username');
✅ 4. 支持的类型
支持所有基本类型和 Map、List:
类型 | 示例 |
---|
String | '张三' |
int | 100 |
double | 3.14 |
bool | true |
List<String> | ['a', 'b'] |
Map<String, dynamic> | {'id': 1, 'name': 'Tom'} |
✅ 5. 多区域存储(类似命名空间)
- 你可以为不同模块使用不同的存储文件(如用户模块/缓存模块)
await GetStorage.init('user');
final userBox = GetStorage('user');userBox.write('token', '123456');
print(userBox.read('token'));
✅ 6. 实时监听值变化(响应式)
box.listen(() {print('本地数据发生变化');
});
box.listenKey('isDark', (value) {print('主题设置变为:$value');
});
✅ 7. 搭配 GetX Controller 使用(推荐)
class AuthController extends GetxController {final storage = GetStorage();var isLoggedIn = false.obs;@overridevoid onInit() {super.onInit();isLoggedIn.value = storage.read('isLoggedIn') ?? false;}void login() {isLoggedIn.value = true;storage.write('isLoggedIn', true);}void logout() {isLoggedIn.value = false;storage.remove('isLoggedIn');}
}
✅ 8. 存储对象(推荐使用 JSON)
final user = {'id': 1,'name': 'Alice','roles': ['admin', 'editor'],
};box.write('user', user);// 读取
Map userData = box.read('user');
如需存储自定义对象,请使用 toJson / fromJson 显式转换。
✅ 9. 总结速查表
操作 | 方法 | 示例 |
---|
初始化 | await GetStorage.init() | 在 main() 中 |
实例化 | GetStorage() | 可传命名空间 |
写入 | .write('key', value) | |
读取 | .read('key') | |
删除 | .remove('key') | |
清空 | .erase() | |
判断 | .hasData('key') | |
监听所有 | .listen((){}) | |
监听某项 | .listenKey('key', callback) | |
使用场景推荐
场景 | 建议用法 |
---|
登录状态 | bool 持久化 + 控制器绑定 |
用户信息 | Map 存储 JSON |
主题模式 | bool 监听并更新 UI |
App 首次启动 | 设置 isFirstRun 标志位 |
临时缓存数据 | write + remove 清理机制 |