Flutter中点击按钮如何获取动态输入框的工资数值?
问题描述
我正在开发一款考勤应用,用于为工人分配工资。我希望将所有工人的工资数据存储到数据库中,但目前遇到的问题是,不知道如何在Flutter中实现点击按钮时获取所有输入框的数值。我是Flutter新手,已提供相关代码及预期效果截图。
模拟器截图
现有代码
ATTENDANCE SCREEN
...rest code... floatingActionButton: FloatingActionButton( onPressed: () { showDialog( context: context, barrierDismissible: false, // user must tap button! builder: (BuildContext context) { return AlertDialog( title: const Text('Upload Patti'), content: SingleChildScrollView( child: ListBody( children: [ TextFormField( controller: _mainWagesController, decoration: const InputDecoration( border: OutlineInputBorder(), hintText: "Enter Amount", prefixIcon: Icon(Icons.wallet, color: Colors.blue), ), ), ], ), ), actions: <Widget>[ ElevatedButton( onPressed: () { Navigator.pop(context); newWages = _mainWagesController.text; setState(() {}); }, child: const Text("Assign Wages"), ), ], ); }, ); }, child: const Icon(Icons.check_circle), ), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(8.00), child: Column(children: [ const SizedBox( height: 20, ), Center( child: Text( "Date : ${DateFormat.yMMMEd().format(DateTime.parse(widget.attendanceDate.toString()))}", style: const TextStyle(fontSize: 20), ), ), const SizedBox( height: 20, ), FutureBuilder( future: SupervisorAttendanceServices.getAttendancesDetailsList( widget.attendanceId), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { var data = snapshot.data['hamal']; return ListView.builder( itemCount: data.length, physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (BuildContext context, int index) { return HamalAttendanceWidget( workerId: data[index]['worker_id'], name: data[index]['worker_name'], wages: newWages, masterAttendanceId: widget.attendanceId, isPrensent: data[index] ['attendance_worker_presense'] .toString()); }); } else if (snapshot.hasError) { return const Center( child: Text("Something went wrong !"), ); } else { return const Center(child: LinearProgressIndicator()); } }, ), ]), ), ), ...rest code
自定义Widget
Widget build(BuildContext context) { return Card( child: Column(children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox( width: 10, height: 50, ), const Icon(FeatherIcons.user), const SizedBox( width: 20, ), Text( widget.name, style: const TextStyle(fontSize: 18), ), ], ), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: 150, height: 60, child: TextFormField( // onChanged: _onChangeHandler, initialValue: widget.wages.toString(), decoration: const InputDecoration( hintText: "Wages", prefixIcon: Icon( Icons.wallet, color: Colors.blue, )), )), ], ) ]), ); }
解决方案
要实现点击按钮获取所有工人工资输入框的数值,核心是给每个工人的输入框绑定独立的控制器,并在父组件中统一管理这些控制器,具体步骤如下:
1. 改造自定义Widget,添加控制器支持
修改HamalAttendanceWidget,新增TextEditingController参数,绑定到输入框,同时允许父组件获取控制器实例:
class HamalAttendanceWidget extends StatelessWidget { final String workerId; final String name; final TextEditingController wagesController; final String masterAttendanceId; final String isPrensent; const HamalAttendanceWidget({ super.key, required this.workerId, required this.name, required this.wagesController, required this.masterAttendanceId, required this.isPrensent, }); @override Widget build(BuildContext context) { return Card( child: Column(children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox(width: 10, height: 50), const Icon(FeatherIcons.user), const SizedBox(width: 20), Text(name, style: const TextStyle(fontSize: 18)), ], ), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox( width: 150, height: 60, child: TextFormField( controller: wagesController, decoration: const InputDecoration( hintText: "Wages", prefixIcon: Icon(Icons.wallet, color: Colors.blue), ), ), ), ], ) ]), ); } }
2. 在父组件中统一管理所有控制器
在Attendance Screen中,定义一个Map存储工人ID与对应输入框控制器的映射,方便后续批量获取数据:
// 存储工人ID和对应工资输入框控制器的Map final Map<String, TextEditingController> _workerWageControllers = {}; // 新增保存按钮逻辑(或修改现有FloatingActionButton的回调) FloatingActionButton( onPressed: () { // 遍历Map,收集所有工人的工资数据 final allWagesData = _workerWageControllers.entries.map((entry) { return { 'worker_id': entry.key, 'wages': entry.value.text, 'master_attendance_id': widget.attendanceId, }; }).toList(); // 此处调用数据库存储接口,传入allWagesData即可 print(allWagesData); // 测试用,打印所有工人工资数据 }, child: const Icon(Icons.save), )
3. 为每个工人创建并传递控制器
在ListView.builder中,为每个工人创建独立的控制器,并传递给自定义Widget:
ListView.builder( itemCount: data.length, physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemBuilder: (BuildContext context, int index) { final workerId = data[index]['worker_id']; // 为每个工人创建唯一的控制器,避免重复创建 final controller = _workerWageControllers.putIfAbsent( workerId, () => TextEditingController(text: newWages), ); return HamalAttendanceWidget( workerId: workerId, name: data[index]['worker_name'], wagesController: controller, masterAttendanceId: widget.attendanceId, isPrensent: data[index]['attendance_worker_presense'].toString(), ); }, )
4. 清理资源避免内存泄漏
在组件销毁时,释放所有控制器资源:
@override void dispose() { _mainWagesController.dispose(); // 释放所有工人的工资输入框控制器 for (var controller in _workerWageControllers.values) { controller.dispose(); } super.dispose(); }
内容的提问来源于stack exchange,提问作者swapnil mane
相关产品推荐
相关产品推荐

