You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:31:04