一个简单的路由跳转、状态管理
目录
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 {
@override
RouteSettings? redirect(String? route) {
final auth = Get.find<AuthController>();
if (!auth.isLoggedIn.value) {
return const RouteSettings(name: '/login');
}
return null; // 正常访问
}
@override
int? 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 {
@override
Widget 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 {
@override
Widget 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 {
@override
Widget 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 {
@override
Widget 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 {
@override
Widget 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 {
@override
RouteSettings? 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;
@override
void 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. 初始化(必须)
-
在 main.dart 的入口函数中初始化:
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('本地数据发生变化');
});
-
你也可以监听某个 key:
box.listenKey('isDark', (value) {
print('主题设置变为:$value');
});
✅ 7. 搭配 GetX Controller 使用(推荐)
-
例如保存登录状态:
class AuthController extends GetxController {
final storage = GetStorage();
var isLoggedIn = false.obs;@override void 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 清理机制 |