Flutter多步骤表单切换后丢失输入值,如何修改代码保留状态?
解决多步骤表单输入值丢失问题
问题根源
表单切换时输入值丢失的核心原因:
- 输入值未与全局状态绑定,页面销毁时数据未持久化
TextFormField未设置初始值,返回旧页面无法恢复内容- 步骤切换逻辑存在错误(如Back按钮跳转至错误步骤)
修改方案
1. 扩展全局状态类(Create.dart)
为每个步骤的表单字段单独添加存储属性,确保数据持久化:
class Create with ChangeNotifier { // 存储第一步表单内容 String? question1Title; String? question1Description; // 存储第二步表单内容 String? question2Title; String? question2Description; int activeIndex = 0; int totalIndex = 6; changeStep(int index) { activeIndex = index; notifyListeners(); } // 可选:重置表单方法 resetForm() { question1Title = null; question1Description = null; question2Title = null; question2Description = null; activeIndex = 0; notifyListeners(); } }
2. 修改第一步表单(form-question1.dart)
绑定全局状态,实现输入值的读取与同步:
class FormQuestion1 extends StatefulWidget { const FormQuestion1({super.key}); static const routeName = '/form-question1'; @override State<FormQuestion1> createState() => _FormQuestion1State(); } class _FormQuestion1State extends State<FormQuestion1> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Consumer<Create>(builder: (context, modal, child) { return Form( key: _formKey, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( // 从全局状态读取初始值 initialValue: modal.question1Title, decoration: const InputDecoration( labelText: 'title', border: OutlineInputBorder(), ), validator: (value) { if (value!.isEmpty) return 'Please enter the title of question'; }, // 实时同步输入到全局状态 onChanged: (value) { modal.question1Title = value; modal.notifyListeners(); }, ), const SizedBox(height: 16), TextFormField( initialValue: modal.question1Description, minLines: 3, maxLines: 5, decoration: const InputDecoration( labelText: 'description', border: OutlineInputBorder(), ), validator: (value) { if (value!.isEmpty || value.length < 30) { return 'Description must be longer'; } }, onChanged: (value) { modal.question1Description = value; modal.notifyListeners(); }, ), Padding( padding: const EdgeInsets.all(10), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 1, child: ElevatedButton( onPressed: modal.activeIndex > 0 ? () { _formKey.currentState?.save(); modal.changeStep(modal.activeIndex - 1); } : null, child: const Text('Back'), ), ), const SizedBox(width: 8), Expanded( flex: 2, child: ElevatedButton( onPressed: () { if (_formKey.currentState?.validate() ?? false) { _formKey.currentState!.save(); // 此处添加提交逻辑 print('提交数据:${modal.question1Title}, ${modal.question1Description}'); } }, child: const Text('Submit'), ), ), const SizedBox(width: 8), Expanded( flex: 1, child: ElevatedButton( onPressed: () { if (_formKey.currentState?.validate() ?? false) { _formKey.currentState!.save(); modal.changeStep(1); } }, child: const Text('Next'), ), ), ], ), ), ], ), ), ); }); } }
3. 修改第二步表单(form-question2.dart)
与第一步逻辑一致,绑定对应状态字段:
class FormQuestion2 extends StatefulWidget { const FormQuestion2({super.key}); static const routeName = '/form-question2'; @override State<FormQuestion2> createState() => _FormQuestion2State(); } class _FormQuestion2State extends State<FormQuestion2> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Consumer<Create>(builder: (context, modal, child) { return Form( key: _formKey, child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( initialValue: modal.question2Title, decoration: const InputDecoration( labelText: 'title', border: OutlineInputBorder(), ), validator: (value) { if (value!.isEmpty) return 'Please enter the title of question'; }, onChanged: (value) { modal.question2Title = value; modal.notifyListeners(); }, ), const SizedBox(height: 16), TextFormField( initialValue: modal.question2Description, minLines: 3, maxLines: 5, decoration: const InputDecoration( labelText: 'description', border: OutlineInputBorder(), ), validator: (value) { if (value!.isEmpty || value.length < 30) { return 'Description must be longer'; } }, onChanged: (value) { modal.question2Description = value; modal.notifyListeners(); }, ), Padding( padding: const EdgeInsets.all(10), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 1, child: ElevatedButton( onPressed: () { _formKey.currentState?.save(); modal.changeStep(0); }, child: const Text('Back'), ), ), const SizedBox(width: 8), Expanded( flex: 2, child: ElevatedButton( onPressed: () { if (_formKey.currentState?.validate() ?? false) { _formKey.currentState!.save(); // 此处添加提交逻辑 print('提交数据:${modal.question2Title}, ${modal.question2Description}'); } }, child: const Text('Submit'), ), ), const SizedBox(width: 8), Expanded( flex: 1, child: ElevatedButton( onPressed: () { if (_formKey.currentState?.validate() ?? false) { _formKey.currentState!.save(); modal.changeStep(2); } }, child: const Text('Next'), ), ), ], ), ), ], ), ), ); }); } }
关键修改点说明
- 状态隔离:为每个步骤的字段单独命名,避免数据覆盖
- 双向绑定:通过
initialValue恢复历史输入,onChanged实时同步到全局状态,确保切换页面时数据不丢失 - 逻辑修正:调整步骤切换逻辑,Back按钮返回上一步,Next按钮跳转至正确的下一个步骤
内容的提问来源于stack exchange,提问作者best_of_man
相关产品推荐
相关产品推荐

