Flutter动态创建自定义Widget时如何获取动态控件的输入文本
解决方案
原生实现方案(无需引入第三方包)
你当前的写法存在两个核心问题,导致无法正常获取输入值:
- 直接维护
List<Widget>存储表单实例,不符合Flutter状态驱动UI的设计逻辑,无法统一管控输入状态 - 手机号、预订号、票号输入框绑定了全局唯一的
TextEditingController,新增多个乘客表单时,所有同名字段会共用同一个控制器,输入内容会互相覆盖,无法拿到每个乘客的独立输入值
正确的实现逻辑是维护数据/控制器列表,通过数据动态渲染UI,步骤如下:
- 定义乘客信息的实体类,每个乘客对应独立的输入控制器,同时统一管理控制器的释放逻辑
class PassengerInfo { final int passengerId; final TextEditingController nameController; final TextEditingController mobileController; final TextEditingController reservationController; final TextEditingController ticketController; PassengerInfo({required this.passengerId}) : nameController = TextEditingController(), mobileController = TextEditingController(), reservationController = TextEditingController(), ticketController = TextEditingController(); void dispose() { nameController.dispose(); mobileController.dispose(); reservationController.dispose(); ticketController.dispose(); } }
- 在页面状态类中,替换原来的Widget列表为乘客数据列表,维护当前乘客的最大序号
List<PassengerInfo> passengerList = [PassengerInfo(passengerId: 1)]; int currentMaxPassengerId = 1;
- 点击添加按钮时,往数据列表中新增乘客实例,通过
setState触发UI刷新,不要直接操作Widget列表
void addNewPassenger() { setState(() { currentMaxPassengerId++; passengerList.add(PassengerInfo(passengerId: currentMaxPassengerId)); }); }
- 改造原来的
textinputPassnger方法,接收单个乘客实体作为参数,输入框绑定实体中对应的独立控制器
Widget buildPassengerFormItem(PassengerInfo passenger) { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox(height: 20), Container( width: 250, height: 30, child: Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), elevation: 5, child: Center( child: Text("Passenger Number ${passenger.passengerId}"), ), ), ), const SizedBox(height: 20), const Text("Passenger Name", style: TextStyle(fontSize: 17)), const SizedBox(height: 15), Inputfield(controller: passenger.nameController), const SizedBox(height: 20), const Text("Mobile", style: TextStyle(fontSize: 17)), const SizedBox(height: 15), Inputfield(controller: passenger.mobileController), const SizedBox(height: 20), const Text("Reservation number", style: TextStyle(fontSize: 17)), const SizedBox(height: 15), Inputfield(controller: passenger.reservationController), const SizedBox(height: 20), const Text("Ticket number", style: TextStyle(fontSize: 17)), const SizedBox(height: 15), Inputfield(controller: passenger.ticketController), ], ); }
- 表单渲染时,直接将数据列表映射为Widget列表即可;需要获取所有输入内容时,遍历数据列表读取每个控制器的text属性就能拿到结构化数据
// 获取所有乘客提交的输入内容 List<Map<String, String>> getAllInputData() { return passengerList.map((item) { return { "passengerId": item.passengerId.toString(), "name": item.nameController.text.trim(), "mobile": item.mobileController.text.trim(), "reservationNo": item.reservationController.text.trim(), "ticketNo": item.ticketController.text.trim(), }; }).toList(); }
注意:页面dispose生命周期中,需要遍历passengerList调用每个实例的dispose方法,释放控制器避免内存泄漏。
可简化动态表单开发的Package
如果不想手动维护控制器、表单校验逻辑,可以使用以下几个常用的成熟表单库,均原生支持动态增减表单项、自动管理输入状态、一键获取全量表单值:
flutter_form_builder:生态最完善的Flutter表单库,内置几乎所有常用输入组件、校验规则,动态表单实现成本极低,不需要手动管理TextEditingControllerreactive_forms:基于响应式状态设计的表单库,支持字段状态实时同步、跨字段联动校验,适合复杂表单场景dynamic_forms:支持通过JSON配置生成表单,适合表单结构需要后端动态下发的业务场景
小提示:你原有代码中"Passenger"存在拼写错误(写成了Passnger、Passanger),建议统一修正,避免后续拼写相关的bug。
内容的提问来源于stack exchange,提问作者Thank for help
相关产品推荐
相关产品推荐

