这个示例完整展示了如何使用 GetX 构建一个功能完备的可复用页面,包括数据获取、表单处理、状态管理和页面导航等核心功能。
-
功能说明:
- 页面加载时自动获取用户数据
- 表单提供实时验证
- 点击更新按钮提交数据
- 右上角按钮可导航到详情页
代码详解
1. 数据模型 (UserModel)
- 定义用户数据结构,包含
id
,name
,email
,age
四个字段 - 提供
fromJson
和toJson
方法用于数据转换 - 作用:标准化数据格式,方便数据传递和存储
2. 控制器 (UserProfileController)
- 状态管理:
user
:存储当前用户数据,使用Rx
使其可观察isLoading
:控制加载状态errorMessage
:存储错误信息
- 表单管理:
- 为每个输入字段创建
TextEditingController
- 提供表单验证方法,确保输入合法性
- 为每个输入字段创建
- 业务逻辑:
fetchUser
:模拟从服务器获取用户数据updateUser
:模拟更新用户数据到服务器navigateToDetailsPage
:导航到详情页
- 资源管理:
- 在控制器销毁时释放表单控制器资源
3. 用户资料页面 (UserProfilePage)
- 依赖注入:
- 使用
Get.put()
初始化控制器,支持通过tag
区分不同实例
- 使用
- 响应式 UI:
- 使用
Obx
包裹需要响应状态变化的部分 - 根据
isLoading
、errorMessage
和user
状态动态显示不同 UI
- 使用
- 表单交互:
- 将控制器的表单验证方法绑定到
TextFormField
- 点击按钮时调用控制器的
updateUser
方法
- 将控制器的表单验证方法绑定到
4. 用户详情页面 (UserDetailsPage)
- 获取控制器:
- 使用
Get.find()
获取已存在的控制器实例
- 使用
- 显示数据:
- 从控制器获取用户数据并显示
核心功能说明
-
状态管理:
- 使用
Rx
和Obx
实现响应式编程,当状态变化时自动更新 UI - 无需手动管理 State,代码更简洁
- 使用
-
依赖注入:
- GetX 提供的依赖注入系统简化了组件间的通信
- 控制器可以在整个应用中共享和复用
-
导航管理:
- 使用
Get.to()
进行页面跳转 - 无需使用 BuildContext,导航更简单
- 使用
-
生命周期管理:
- 控制器自动管理生命周期,在需要时创建,不再使用时销毁
- 通过
onClose()
方法释放资源,防止内存泄漏
使用方法
-
添加依赖:
yaml
dependencies: get: ^4.6.5
-
集成到应用:
dart
// 在路由中使用 MaterialApp( home: UserProfilePage(userId: '123'), );
import 'package:flutter/material.dart'; import 'package:get/get.dart'; // 数据模型 - 定义用户数据结构 class UserModel { final String id; final String name; final String email; final int age; UserModel({ required this.id, required this.name, required this.email, required this.age, }); // 从 JSON 创建 UserModel factory UserModel.fromJson(Map<String, dynamic> json) { return UserModel( id: json['id'], name: json['name'], email: json['email'], age: json['age'], ); } // 转换为 JSON Map<String, dynamic> toJson() { return { 'id': id, 'name': name, 'email': email, 'age': age, }; } } // 控制器 - 处理业务逻辑和状态管理 class UserProfileController extends GetxController { // 响应式状态 - 当值变化时自动更新 UI final Rx<UserModel?> user = Rx<UserModel?>(null); final RxBool isLoading = false.obs; final RxString errorMessage = ''.obs; // 表单控制器 - 管理输入框内容 final TextEditingController nameController = TextEditingController(); final TextEditingController emailController = TextEditingController(); final TextEditingController ageController = TextEditingController(); // 表单验证方法 String? validateName(String? value) { if (value == null || value.isEmpty) { return '姓名不能为空'; } return null; } String? validateEmail(String? value) { if (value == null || value.isEmpty) { return '邮箱不能为空'; } if (!GetUtils.isEmail(value)) { return '无效的邮箱地址'; } return null; } String? validateAge(String? value) { if (value == null || value.isEmpty) { return '年龄不能为空'; } if (int.tryParse(value) == null) { return '年龄必须是数字'; } return null; } // 获取用户数据 - 模拟 API 调用 Future<void> fetchUser(String userId) async { isLoading.value = true; errorMessage.value = ''; try { // 模拟网络延迟 await Future.delayed(const Duration(seconds: 1)); // 模拟 API 返回数据 final mockUser = UserModel( id: userId, name: '张三', email: 'zhangsan@example.com', age: 30, ); user.value = mockUser; _initializeFormFields(); } catch (e) { errorMessage.value = '加载用户数据失败'; } finally { isLoading.value = false; } } // 初始化表单字段 void _initializeFormFields() { if (user.value != null) { nameController.text = user.value!.name; emailController.text = user.value!.email; ageController.text = user.value!.age.toString(); } } // 更新用户数据 - 模拟 API 调用 Future<void> updateUser() async { if (user.value == null) return; isLoading.value = true; errorMessage.value = ''; try { // 模拟网络延迟 await Future.delayed(const Duration(seconds: 1)); // 更新用户数据 final updatedUser = UserModel( id: user.value!.id, name: nameController.text, email: emailController.text, age: int.parse(ageController.text), ); user.value = updatedUser; Get.snackbar('成功', '个人资料更新成功', backgroundColor: Colors.green, colorText: Colors.white); } catch (e) { errorMessage.value = '更新个人资料失败'; } finally { isLoading.value = false; } } // 导航到详情页 void navigateToDetailsPage() { if (user.value != null) { Get.to(() => const UserDetailsPage()); } } @override void onClose() { // 释放资源 - 防止内存泄漏 nameController.dispose(); emailController.dispose(); ageController.dispose(); super.onClose(); } } // 用户资料页面 - 可复用组件 class UserProfilePage extends StatelessWidget { final String userId; const UserProfilePage({Key? key, this.userId = '1'}) : super(key: key); @override Widget build(BuildContext context) { // 使用依赖注入初始化控制器 - 支持多实例 final UserProfileController controller = Get.put(UserProfileController(), tag: userId); // 页面初始化时获取用户数据 if (controller.user.value == null) { controller.fetchUser(userId); } return Scaffold( appBar: AppBar( title: const Text('个人资料'), actions: [ IconButton( icon: const Icon(Icons.info), onPressed: controller.navigateToDetailsPage, ), ], ), body: Obx(() { // 根据状态显示不同的 UI if (controller.isLoading.value) { return const Center(child: CircularProgressIndicator()); } if (controller.errorMessage.value.isNotEmpty) { return Center( child: Text( controller.errorMessage.value, style: const TextStyle(color: Colors.red), ), ); } if (controller.user.value == null) { return const Center(child: Text('无用户数据')); } return Padding( padding: const EdgeInsets.all(16.0), child: Form( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ TextFormField( controller: controller.nameController, decoration: const InputDecoration(labelText: '姓名'), validator: controller.validateName, ), TextFormField( controller: controller.emailController, decoration: const InputDecoration(labelText: '邮箱'), validator: controller.validateEmail, ), TextFormField( controller: controller.ageController, decoration: const InputDecoration(labelText: '年龄'), keyboardType: TextInputType.number, validator: controller.validateAge, ), const SizedBox(height: 20), ElevatedButton( onPressed: controller.updateUser, child: const Text('更新资料'), ), ], ), ), ); }), ); } } // 用户详情页面 - 演示导航功能 class UserDetailsPage extends StatelessWidget { const UserDetailsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { // 获取已存在的控制器实例 final UserProfileController controller = Get.find<UserProfileController>(); return Scaffold( appBar: AppBar(title: const Text('用户详情')), body: Center( child: controller.user.value == null ? const Text('无用户数据') : Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('ID: ${controller.user.value!.id}'), Text('姓名: ${controller.user.value!.name}'), Text('邮箱: ${controller.user.value!.email}'), Text('年龄: ${controller.user.value!.age}'), ], ), ), ); } }