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

Flutter动态添加TextField问题:仅获取最后一条表单数据

解决动态添加表单仅保存最后一条数据的问题

嘿,我明白你遇到的困扰了!你每次添加新宠物表单后,所有输入最终都只存在最后一个键里,这是Dart闭包的一个常见“坑”,我来帮你搞定它。

问题根源:闭包捕获的是变量引用而非值

在你的_add方法里,每个TextField的onChanged回调都是一个闭包,它捕获的是_index变量的引用,而不是你添加表单那一刻_index的具体值。当你后续点击“Add another”让_index递增后,所有之前创建的TextField回调里的$_index都会指向最新的_index值——这就导致不管你在哪个宠物输入框输入内容,最终都会把值覆盖到最后一个生成的键(比如pet6、name6)上。

修复方案:用局部变量固定当前索引

解决方法很简单:在每次添加新表单时,把当前的_index值保存到一个局部变量里,让闭包捕获这个固定的局部变量值,而不是随时间变化的_index引用。修改后的_add方法如下:

void _add() {
  // 先把当前的索引值存到局部变量,避免闭包捕获引用
  int currentIndex = _index;
  _myPets = List.from(_myPets)
    ..add(Column(
      children: <Widget>[
        ListTile(
          leading: Text('Pet $currentIndex : '),
          title: TextField(
            onChanged: (val) => _formdata['pet$currentIndex'] = val,
          ),
        ),
        ListTile(
          leading: Text('Name of Pet $currentIndex : '),
          title: TextField(
            onChanged: (val) {
              _formdata['name$currentIndex'] = val;
            },
          ),
        ),
      ],
    ));
  setState(() => ++_index);
}

这样一来,每个宠物表单的TextField回调都会绑定到添加时的currentIndex固定值,后续_index的变化不会影响到之前的回调。现在你再输入各个宠物的信息,点击Save按钮打印_formdata,就能看到所有宠物的数据都正确保存了,比如{pet1: "1", name1: "旺财", pet2: "2", name2: "咪咪"}这样的结果。

额外优化建议:用对象列表管理宠物数据

虽然上面的方法能解决问题,但用Map<String, String>存储多组宠物数据的方式不够直观,后期维护也麻烦。你可以创建一个Pet类,用列表来管理所有宠物:

// 定义Pet类
class Pet {
  String age;
  String name;
  Pet({this.age = "", this.name = ""});
}

// 修改状态类里的变量
class _MyPetsState extends State<MyPets> {
  List<Pet> _pets = [];
  int _index = 1;

  void _add() {
    _pets.add(Pet());
    setState(() => ++_index);
  }

  @override
  void initState() {
    super.initState();
    _add();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () => print(_pets.map((pet) => {"age": pet.age, "name": pet.name}).toList()),
        child: Text('Save'),
      ),
      appBar: AppBar(
        title: Text('Add your pets'),
        actions: <Widget>[
          FlatButton(
            child: Text('Add another'),
            onPressed: _add,
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: _pets.length,
        itemBuilder: (context, index) {
          return Column(
            children: <Widget>[
              ListTile(
                leading: Text('Pet ${index + 1} : '),
                title: TextField(
                  onChanged: (val) => _pets[index].age = val,
                ),
              ),
              ListTile(
                leading: Text('Name of Pet ${index + 1} : '),
                title: TextField(
                  onChanged: (val) => _pets[index].name = val,
                ),
              ),
            ],
          );
        },
      ),
    );
  }
}

这种方式不仅代码结构更清晰,还能避免手动管理Map键名的麻烦,后期扩展宠物属性也更方便。

内容的提问来源于stack exchange,提问作者CodeforCore

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:56:12