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

Flutter动态添加/移除表单字段实现方案咨询

Flutter 实现动态表单字段(类似czMore功能)

不用找插件,自己实现其实很简单,核心就是用列表管理表单条目,配合setState或状态管理库刷新UI。下面是具体实现步骤和代码示例:

1. 定义表单数据模型

先把每个表单条目的数据封装成类,包含你需要的字段(设备类型、型号、解决方案),并设置默认值:

class DeviceSolution {
  String deviceType;
  String model;
  String solution;

  DeviceSolution({
    this.deviceType = "默认设备类型",
    this.model = "默认型号",
    this.solution = "默认解决方案",
  });
}

2. 封装单个表单条目Widget

把一组字段封装成独立Widget,方便复用,同时提供回调更新数据:

class DeviceFormItem extends StatelessWidget {
  final DeviceSolution item;
  final Function(DeviceSolution) onUpdate;
  final Function()? onDelete; // 可选:添加删除功能

  const DeviceFormItem({
    super.key,
    required this.item,
    required this.onUpdate,
    this.onDelete,
  });

  @override
  Widget build(BuildContext context) {
    final typeController = TextEditingController(text: item.deviceType);
    final modelController = TextEditingController(text: item.model);
    final solutionController = TextEditingController(text: item.solution);

    // 监听输入更新对应字段
    typeController.addListener(() {
      onUpdate(DeviceSolution(
        deviceType: typeController.text,
        model: item.model,
        solution: item.solution,
      ));
    });

    modelController.addListener(() {
      onUpdate(DeviceSolution(
        deviceType: item.deviceType,
        model: modelController.text,
        solution: item.solution,
      ));
    });

    solutionController.addListener(() {
      onUpdate(DeviceSolution(
        deviceType: item.deviceType,
        model: item.model,
        solution: solutionController.text,
      ));
    });

    return Card(
      margin: const EdgeInsets.symmetric(vertical: 8),
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              decoration: const InputDecoration(labelText: "设备类型"),
              controller: typeController,
            ),
            TextField(
              decoration: const InputDecoration(labelText: "型号"),
              controller: modelController,
            ),
            TextField(
              decoration: const InputDecoration(labelText: "解决方案"),
              maxLines: 3,
              controller: solutionController,
            ),
            if (onDelete != null)
              TextButton.icon(
                onPressed: onDelete,
                icon: const Icon(Icons.delete),
                label: const Text("删除"),
              ),
          ],
        ),
      ),
    );
  }
}

3. 主页面管理表单列表

在主页面的State类里维护表单条目列表,实现「添加更多」按钮的逻辑:

class DynamicFormPage extends StatefulWidget {
  const DynamicFormPage({super.key});

  @override
  State<DynamicFormPage> createState() => _DynamicFormPageState();
}

class _DynamicFormPageState extends State<DynamicFormPage> {
  final List<DeviceSolution> _formItems = [DeviceSolution()]; // 初始一个条目

  void _addNewItem() {
    setState(() {
      _formItems.add(DeviceSolution()); // 添加带默认值的新条目
    });
  }

  void _updateItem(int index, DeviceSolution newItem) {
    setState(() {
      _formItems[index] = newItem;
    });
  }

  void _deleteItem(int index) {
    setState(() {
      _formItems.removeAt(index);
      // 至少保留一个条目
      if (_formItems.isEmpty) _formItems.add(DeviceSolution());
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("动态设备表单")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: _formItems.length,
                itemBuilder: (context, index) {
                  return DeviceFormItem(
                    item: _formItems[index],
                    onUpdate: (newItem) => _updateItem(index, newItem),
                    onDelete: _formItems.length > 1 ? () => _deleteItem(index) : null,
                  );
                },
              ),
            ),
            const SizedBox(height: 16),
            ElevatedButton.icon(
              onPressed: _addNewItem,
              icon: const Icon(Icons.add),
              label: const Text("添加更多"),
            ),
          ],
        ),
      ),
    );
  }
}

4. 优化建议

  • 表单验证:提交时遍历_formItems,检查每个条目的字段是否符合要求,比如非空校验。
  • 性能优化:如果条目数量多,ListView.builder已经帮你做了懒加载,避免一次性渲染所有条目。
  • 状态管理:如果表单逻辑复杂(比如和其他页面共享数据),可以用Provider、Riverpod替代setState,让状态管理更清晰。
  • 控制器优化:上面的示例每次重建DeviceFormItem都会创建新的控制器,实际可以在Widget里缓存控制器,或者用ValueListenableBuilder减少不必要的重建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 13:57:16