Flutter中如何持久化保存动态多表单的TextFormField数据
解决Flutter动态多表单页面切换后数据丢失的问题
方案1:页面保活(会话内临时留存)
如果仅需在返回主菜单再进入时保留页面数据、避免页面重建,可通过AutomaticKeepAliveClientMixin实现页面保活,阻止页面被销毁。
实现步骤:
- 在主菜单项页面的State类中混入
AutomaticKeepAliveClientMixin - 重写
wantKeepAlive方法返回true - 在
build方法中必须调用super.build(context)
示例代码:
class DynamicFormPage extends StatefulWidget { const DynamicFormPage({super.key}); @override State<DynamicFormPage> createState() => _DynamicFormPageState(); } class _DynamicFormPageState extends State<DynamicFormPage> with AutomaticKeepAliveClientMixin { // 存储动态表单数据的列表,可替换为自定义模型 List<Map<String, String>> formList = []; @override bool get wantKeepAlive => true; @override Widget build(BuildContext context) { super.build(context); // 必须调用以触发保活逻辑 return Scaffold( appBar: AppBar(title: const Text("动态表单")), body: ListView.builder( itemCount: formList.length, itemBuilder: (context, index) { return TextFormField( initialValue: formList[index]['content'], onChanged: (value) { setState(() { formList[index]['content'] = value; }); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { formList.add({'content': ''}); }); }, child: const Icon(Icons.add), ), ); } }
方案2:全局状态管理(跨页面共享数据)
若需要在多个页面共享表单数据,或希望会话内页面重建后数据不丢失,可使用状态管理工具(如Riverpod、Provider)将数据存储在全局状态中,页面依赖状态渲染UI。
以Riverpod为例:
- 定义表单模型与状态管理类
// 表单数据模型 class FormItem { String content; FormItem({required this.content}); } // 状态管理类 class FormListNotifier extends StateNotifier<List<FormItem>> { FormListNotifier() : super([]); // 添加新表单 void addForm() { state = [...state, FormItem(content: '')]; } // 更新表单内容 void updateForm(int index, String content) { final updatedList = List<FormItem>.from(state); updatedList[index] = FormItem(content: content); state = updatedList; } } // 定义全局Provider final formListProvider = StateNotifierProvider<FormListNotifier, List<FormItem>>((ref) { return FormListNotifier(); });
- 在动态表单页面中使用Provider:
class DynamicFormPage extends ConsumerWidget { const DynamicFormPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final formList = ref.watch(formListProvider); return Scaffold( appBar: AppBar(title: const Text("动态表单")), body: ListView.builder( itemCount: formList.length, itemBuilder: (context, index) { return TextFormField( initialValue: formList[index].content, onChanged: (value) { ref.read(formListProvider.notifier).updateForm(index, value); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: () { ref.read(formListProvider.notifier).addForm(); }, child: const Icon(Icons.add), ), ); } }
方案3:本地持久化(永久留存,APP重启后仍保留)
如果需要APP重启后数据不丢失,需将表单数据持久化到本地存储,简单数据可用SharedPreferences,复杂模型推荐用Hive或Isar。
以Hive为例:
- 初始化Hive并定义模型Adapter:
// 先在pubspec.yaml添加依赖 // hive: ^2.2.3 // hive_flutter: ^1.1.0 // build_runner: ^2.4.4 // hive_generator: ^1.1.5 // 表单模型 @HiveType(typeId: 0) class FormItem extends HiveObject { @HiveField(0) String content; FormItem({required this.content}); } // 运行命令生成Adapter: flutter packages pub run build_runner build
- 在动态表单页面中读写本地数据:
class DynamicFormPage extends StatefulWidget { const DynamicFormPage({super.key}); @override State<DynamicFormPage> createState() => _DynamicFormPageState(); } class _DynamicFormPageState extends State<DynamicFormPage> { late Box<FormItem> formBox; List<FormItem> formList = []; @override void initState() { super.initState(); // 打开Hive存储盒子 formBox = Hive.box<FormItem>('form_box'); // 从本地加载已有数据 loadFormData(); } void loadFormData() { setState(() { formList = formBox.values.toList(); }); } // 保存单个表单数据到本地 void saveFormItem(int index, String content) { final formItem = FormItem(content: content); formBox.putAt(index, formItem); } // 添加新表单并保存到本地 void addForm() { final newForm = FormItem(content: ''); formBox.add(newForm); loadFormData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("动态表单")), body: ListView.builder( itemCount: formList.length, itemBuilder: (context, index) { return TextFormField( initialValue: formList[index].content, onChanged: (value) { saveFormItem(index, value); }, ); }, ), floatingActionButton: FloatingActionButton( onPressed: addForm, child: const Icon(Icons.add), ), ); } }
内容的提问来源于stack exchange,提问作者Vivek Rai
相关产品推荐
相关产品推荐

