Flutter GetX 状态管理完全指南
·
Flutter GetX 状态管理完全指南
引言
GetX 是 Flutter 社区中最流行的状态管理库之一,它提供了简单、高效且功能丰富的状态管理解决方案。本文将深入探讨 GetX 的各种用法和高级技巧。
基础概念回顾
GetX 的核心功能
- 状态管理: 响应式状态管理
- 路由管理: 无需上下文的导航
- 依赖注入: 简单的依赖管理
- 国际化: 多语言支持
- 主题管理: 动态主题切换
核心概念
- GetX Controller: 管理状态的控制器
- Obx: 响应式观察者组件
- Get.put(): 注入依赖
- Get.find(): 获取依赖
高级技巧一:基础状态管理
创建 Controller
import 'package:get/get.dart';
class CounterController extends GetxController {
final count = 0.obs;
void increment() => count.value++;
void decrement() => count.value--;
void reset() => count.value = 0;
}
使用 Controller
class CounterScreen extends StatelessWidget {
final controller = Get.put(CounterController());
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Column(
children: [
Obx(() => Text('Count: ${controller.count.value}')),
ElevatedButton(
onPressed: controller.increment,
child: const Text('Increment'),
),
],
),
),
);
}
}
响应式变量
class UserController extends GetxController {
final user = User().obs;
void updateUser(User newUser) {
user.value = newUser;
}
void updateUserName(String name) {
user.update((user) {
user?.name = name;
});
}
}
高级技巧二:路由管理
基本导航
// 导航到新页面
Get.to(NextScreen());
// 导航并返回数据
final result = await Get.to(NextScreen());
// 弹出当前页面
Get.back();
// 弹出并返回数据
Get.back(result: 'result');
// 清除所有页面并导航
Get.offAll(HomeScreen());
命名路由
void main() {
runApp(GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => HomeScreen()),
GetPage(name: '/detail', page: () => DetailScreen()),
],
));
}
// 使用命名路由
Get.toNamed('/detail');
// 带参数的命名路由
Get.toNamed('/detail', arguments: {'id': 1});
// 获取参数
final args = Get.arguments as Map;
自定义过渡动画
GetPage(
name: '/detail',
page: () => DetailScreen(),
transition: Transition.fade,
duration: const Duration(milliseconds: 500),
);
高级技巧三:依赖注入
注入依赖
void main() {
Get.put(ApiService());
Get.put(UserController());
runApp(const MyApp());
}
// 在任意地方获取
final apiService = Get.find<ApiService>();
final userController = Get.find<UserController>();
懒加载
Get.lazyPut(() => ApiService());
Get.lazyPut(() => UserController());
单例模式
Get.put<ApiService>(ApiService(), permanent: true);
高级技巧四:国际化
配置国际化
void main() {
runApp(GetMaterialApp(
translations: Messages(),
locale: const Locale('zh', 'CN'),
fallbackLocale: const Locale('en', 'US'),
));
}
class Messages extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': {
'hello': 'Hello',
'welcome': 'Welcome',
},
'zh_CN': {
'hello': '你好',
'welcome': '欢迎',
},
};
}
使用国际化
Text('hello'.tr);
Text('welcome'.tr);
实战案例:购物车管理
class CartController extends GetxController {
final items = <CartItem>[].obs;
int get totalItems => items.length;
double get totalPrice => items.fold(0, (sum, item) => sum + item.price);
void addItem(CartItem item) {
items.add(item);
}
void removeItem(CartItem item) {
items.remove(item);
}
void clearCart() {
items.clear();
}
}
class CartItem {
final String id;
final String name;
final double price;
CartItem({required this.id, required this.name, required this.price});
}
class CartScreen extends StatelessWidget {
final controller = Get.find<CartController>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Cart')),
body: Obx(() {
if (controller.items.isEmpty) {
return const Center(child: Text('Cart is empty'));
}
return ListView.builder(
itemCount: controller.items.length,
itemBuilder: (context, index) {
final item = controller.items[index];
return ListTile(
title: Text(item.name),
subtitle: Text('\$${item.price}'),
trailing: IconButton(
icon: const Icon(Icons.remove),
onPressed: () => controller.removeItem(item),
),
);
},
);
}),
bottomNavigationBar: Obx(() => Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Total: \$${controller.totalPrice}'),
ElevatedButton(
onPressed: controller.totalItems > 0 ? controller.clearCart : null,
child: const Text('Clear Cart'),
),
],
),
)),
);
}
}
实战案例:主题切换
class ThemeController extends GetxController {
final isDarkMode = false.obs;
ThemeData get theme => isDarkMode.value ? ThemeData.dark() : ThemeData.light();
void toggleTheme() {
isDarkMode.value = !isDarkMode.value;
}
}
class ThemeToggle extends StatelessWidget {
final controller = Get.find<ThemeController>();
@override
Widget build(BuildContext context) {
return Obx(() => Switch(
value: controller.isDarkMode.value,
onChanged: (_) => controller.toggleTheme(),
));
}
}
void main() {
Get.put(ThemeController());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final controller = Get.find<ThemeController>();
return Obx(() => GetMaterialApp(
theme: controller.theme,
home: const HomePage(),
));
}
}
实战案例:用户认证
class AuthController extends GetxController {
final user = Rxn<User>();
bool get isLoggedIn => user.value != null;
Future<void> login(String email, String password) async {
user.value = await authService.login(email, password);
}
void logout() {
user.value = null;
}
}
class AuthGuard extends StatelessWidget {
final Widget child;
const AuthGuard({super.key, required this.child});
@override
Widget build(BuildContext context) {
final controller = Get.find<AuthController>();
return Obx(() {
if (!controller.isLoggedIn) {
return const LoginPage();
}
return child;
});
}
}
// 使用
void main() {
Get.put(AuthController());
runApp(GetMaterialApp(
home: AuthGuard(child: const HomePage()),
));
}
常见问题与解决方案
Q1:状态不更新?
A:确保使用 .obs 和 Obx():
// 正确
final count = 0.obs;
Obx(() => Text('${count.value}'));
// 错误
int count = 0; // 没有使用 .obs
Q2:Get.find() 找不到?
A:确保先注入依赖:
// 在main中注入
Get.put(MyController());
// 然后在组件中使用
final controller = Get.find<MyController>();
Q3:路由导航没有上下文?
A:使用 GetMaterialApp 替代 MaterialApp:
// 正确
GetMaterialApp(home: HomePage());
// 错误
MaterialApp(home: HomePage()); // 无法使用 Get.to()
最佳实践
1. 分离业务逻辑
class UserRepository {
Future<User> getUser(int id) => api.getUser(id);
}
class UserController extends GetxController {
final repository = Get.find<UserRepository>();
final user = Rxn<User>();
Future<void> loadUser(int id) async {
user.value = await repository.getUser(id);
}
}
2. 使用 Rxn 处理空值
// 推荐
final user = Rxn<User>();
// 不推荐
final user = User().obs; // 需要处理空值
3. 及时释放资源
class MyController extends GetxController {
late StreamSubscription subscription;
@override
void onInit() {
super.onInit();
subscription = stream.listen((data) {
// 处理数据
});
}
@override
void onClose() {
subscription.cancel();
super.onClose();
}
}
总结
GetX 是一个功能强大的状态管理库。通过本文的学习,你应该能够:
- 创建和使用 GetX Controller
- 使用响应式状态管理
- 实现路由导航
- 处理依赖注入
- 实现国际化和主题切换
掌握这些技巧,能够帮助你创建更加高效和可维护的应用程序。
更多推荐
所有评论(0)