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

如何在TextFormField列表中间动态添加带初始化数据的字段?

问题原因

核心问题在于TextFormField的initialValue仅在组件首次构建时生效。当你在列表中间插入新字段后,ListView.separated会复用已有的TextFormField组件,而非重新创建,导致新插入位置后的字段无法正确加载对应的数据,出现数据错位。

修复方案

有两种可靠的修复方式,推荐使用第二种(Controller方式),更稳定且易于维护:

方案一:为每个TextFormField添加唯一Key

通过给每个TextFormField绑定唯一的Key,强制Flutter在列表结构变化时重新构建对应的输入框组件,确保initialValue正确更新。

修改后的代码:

import 'package:flutter/material.dart';

class DynamicFormWidget extends StatefulWidget {
  const DynamicFormWidget({Key? key}) : super(key: key);

  @override
  State<DynamicFormWidget> createState() => _DynamicFormWidgetState();
}

class _DynamicFormWidgetState extends State<DynamicFormWidget> {
  List<String?> names = [null];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('动态表单'),
      ),
      body: ListView.separated(
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
        itemBuilder: (builderContext, index) => Row(
          children: [
            Flexible(
              child: TextFormField(
                key: ValueKey('name_field_$index'), // 添加唯一Key
                initialValue: names[index],
                onChanged: (name) {
                  names[index] = name;
                  debugPrint(names.toString());
                },
                decoration: InputDecoration(
                  hintText: '输入姓名',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8)
                  )
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: IconButton(
                onPressed: () {
                  setState(() {
                    if(index + 1 == names.length){
                      names.add(null);
                      debugPrint('添加: $names');
                    } else {
                      names.insert(index + 1, null);
                      debugPrint('在位置[${index+1}]添加: $names');
                    }
                  });
                },
                color: Colors.green,
                iconSize: 32,
                icon: const Icon(Icons.add_circle)),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: IconButton(
                onPressed: (index == 0 && names.length == 1)
                    ? null
                    : () {
                  setState(() {
                    names.removeAt(index);
                  });
                  debugPrint('移除位置[$index]: $names');
                },
                color: Colors.red,
                iconSize: 32,
                icon: const Icon(Icons.remove_circle)),
            ),
          ],
        ),
        separatorBuilder: (separatorContext, index) => const SizedBox(
          height: 16,
        ),
        itemCount: names.length,
      ),
    );
  }
}

方案二:使用TextEditingController管理每个输入框(推荐)

通过为每个字段创建独立的TextEditingController,直接控制输入框的内容,完全避免组件复用带来的问题,同时能更灵活地操作输入内容。

修改后的代码:

import 'package:flutter/material.dart';

class DynamicFormWidget extends StatefulWidget {
  const DynamicFormWidget({Key? key}) : super(key: key);

  @override
  State<DynamicFormWidget> createState() => _DynamicFormWidgetState();
}

class _DynamicFormWidgetState extends State<DynamicFormWidget> {
  // 用List存储每个输入框的Controller
  List<TextEditingController> controllers = [TextEditingController()];

  @override
  void dispose() {
    // 记得销毁所有Controller,避免内存泄漏
    for (var controller in controllers) {
      controller.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('动态表单'),
      ),
      body: ListView.separated(
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
        itemBuilder: (builderContext, index) => Row(
          children: [
            Flexible(
              child: TextFormField(
                controller: controllers[index], // 绑定对应Controller
                decoration: InputDecoration(
                  hintText: '输入姓名',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8)
                  )
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: IconButton(
                onPressed: () {
                  setState(() {
                    if(index + 1 == controllers.length){
                      controllers.add(TextEditingController());
                      debugPrint('添加新字段');
                    } else {
                      controllers.insert(index + 1, TextEditingController());
                      debugPrint('在位置[${index+1}]添加新字段');
                    }
                  });
                },
                color: Colors.green,
                iconSize: 32,
                icon: const Icon(Icons.add_circle)),
            ),
            Padding(
              padding: const EdgeInsets.all(8),
              child: IconButton(
                onPressed: (index == 0 && controllers.length == 1)
                    ? null
                    : () {
                  setState(() {
                    // 移除前先销毁Controller
                    controllers[index].dispose();
                    controllers.removeAt(index);
                  });
                  debugPrint('移除位置[$index]的字段');
                },
                color: Colors.red,
                iconSize: 32,
                icon: const Icon(Icons.remove_circle)),
            ),
          ],
        ),
        separatorBuilder: (separatorContext, index) => const SizedBox(
          height: 16,
        ),
        itemCount: controllers.length,
      ),
    );
  }
}
说明
  • 方案一通过Key强制组件重建,简单直接,但在列表项较多时可能影响性能(因为会重建多个组件)。
  • 方案二使用Controller管理输入内容,是Flutter中处理动态输入框的标准做法,性能更优,且逻辑更清晰,推荐使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 09:05:14