Flutter动态添加TextFormField多输入框值同步问题
问题根因
所有动态生成的输入框共用了同一个TextEditingController实例。在Flutter中,输入框的内容完全由绑定的控制器控制,多个输入框绑定同一个控制器时,输入内容会自动同步到所有绑定的输入框。
Flutter不支持PHP里sets$numberOfTextFields这种动态变量名的写法,这类多实例场景需要用集合来管理独立的控制器实例。
修复步骤
- 替换单个控制器为控制器列表,每个输入框对应列表里一个独立的控制器实例
- 生成输入框时按索引绑定对应位置的控制器
- 点击新增输入框时,同步往控制器列表添加新的控制器实例
- 页面销毁时遍历释放所有控制器,避免内存泄漏
- 提交表单时遍历控制器列表,获取所有输入框的内容
核心修改代码
- 替换状态类中的控制器定义、初始化、销毁逻辑
class _EventEditingPageState extends State<EventEditingPage> { final _formKey = GlobalKey<FormState>(); // 用列表存储所有输入框的控制器,初始默认1个 List<TextEditingController> setsControllers = [TextEditingController()]; int numberOfTextFields = 1; @override void initState() { super.initState(); // 编辑现有事件时给第一个输入框赋值 if(widget.event != null){ setsControllers[0].text = widget.event!.Sets; } } @override void dispose() { // 遍历释放所有控制器 for (var controller in setsControllers) { controller.dispose(); } super.dispose(); } // ... 其余原有代码 }
- 修改输入框构建方法,按索引绑定对应控制器
// 传入索引参数区分不同输入框 Widget buildExerciseComplete(int index) => Container( padding: EdgeInsets.all(5.0), decoration: BoxDecoration( color: Color.fromARGB(255, 255, 200, 200), borderRadius: BorderRadius.circular(5.0), border: Border.all(width: 2.0), ), height: 50, child: Row( children: <Widget>[ Expanded( child: Row( children: <Widget>[ Expanded(child: buildSets(index)), ], ), ), ], ), ); Widget buildSets(int index) => TextFormField( keyboardType: TextInputType.number, inputFormatters: <TextInputFormatter>[ FilteringTextInputFormatter.digitsOnly ], style: TextStyle(fontSize: 15), decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Sets ${index + 1}', ), onFieldSubmitted: (_) => saveForm, validator: (sets) => sets != null && sets.isEmpty ? 'Sets cannot be empty' : null, // 绑定当前索引对应的独立控制器 controller: setsControllers[index], );
- 修改动态生成逻辑和新增按钮逻辑
@override Widget build(BuildContext context) => Scaffold( appBar: AppBar( leading: CloseButton(), actions: buildEditingActions(), backgroundColor: Colors.red, ), body: SingleChildScrollView( padding: EdgeInsets.all(12), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ // 循环时传入索引 for(int i = 0 ; i < numberOfTextFields ; i++) buildExerciseComplete(i), buildAddMore(), ], ), ), ), ); Widget buildAddMore() => ElevatedButton( onPressed: () { setState((){ numberOfTextFields++; // 新增输入框时同步添加新的独立控制器 setsControllers.add(TextEditingController()); }); }, child: Text('Add new exercise'), );
- 修改表单提交逻辑,获取所有输入框的值
Future saveForm() async { final isValid = _formKey.currentState!.validate(); if (isValid) { // 遍历控制器拿到所有输入框的内容 List<String> allSetValues = setsControllers.map((e) => e.text).toList(); // 后续按业务需求处理allSetValues即可 // 示例:如果原有Event需要接收所有值,可自行调整Event类的字段类型 // final event = Event(Sets: allSetValues); } }
提示:如果后续需要给每个输入框加删除功能,删除对应行时要同步移除列表里对应索引的控制器并调用dispose,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Ko1ind
相关产品推荐
相关产品推荐

