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

Flutter Form Builder动态表单字段删除后UI与实际状态不一致问题

Flutter Form Builder动态表单UI不同步问题

我在测试Flutter Form Builder的动态表单功能,表单支持自由添加、删除字段。原代码存在问题:点击字段对应的删除按钮时,总是删除最新添加的FormBuilderTextField,而非目标字段。

我尝试修复后,表单底层状态已符合预期(点击提交后打印的_formKey状态正确),但UI未同步更新,仍显示最新字段被删除的错误状态:

  • 初始状态:表单包含一个起始字段和3个动态添加的字段(字段#1、#2、#3)
  • 点击字段#3的删除按钮后:UI错误删除了最新字段,同时底层状态也异常
  • 点击提交按钮后:底层状态恢复正确,但UI依旧显示错误状态

修改后的dynamic_fields.dart代码如下:

import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';

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

  @override
  State<DynamicFields> createState() => _DynamicFieldsState();
}

class _DynamicFieldsState extends State<DynamicFields> {
  final _formKey = GlobalKey<FormBuilderState>();
  final Map<int, Widget> fields = {};
  int idCounter = 1;
  String savedValue = '';

  @override
  void initState() {
    savedValue = _formKey.currentState?.value.toString() ?? '';
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FormBuilder(
      key: _formKey,
      // IMPORTANT to remove all references from dynamic field when delete
      clearValueOnUnregister: true,
      child: Column(
        children: <Widget>[
          const SizedBox(height: 20),
          FormBuilderTextField(
            name: 'name',
            validator: FormBuilderValidators.required(),
            decoration: const InputDecoration(
              label: Text('Started field'),
            ),
          ),
          ...fields.values,
          const SizedBox(height: 10),
          Row(
            children: <Widget>[
              Expanded(
                child: MaterialButton(
                  color: Theme.of(context).colorScheme.secondary,
                  child: const Text(
                    "Submit",
                    style: TextStyle(color: Colors.white),
                  ),
                  onPressed: () {
                    _formKey.currentState!.saveAndValidate();
                    setState(() {
                      savedValue = "Submit button pressed - current form state: ${_formKey.currentState!.value.toString()}";
                          _formKey.currentState?.value.toString() ?? '';
                    });
                  },
                ),
              ),
              const SizedBox(width: 20),
              Expanded(
                child: MaterialButton(
                  color: Theme.of(context).colorScheme.secondary,
                  child: const Text(
                    "Add field",
                    style: TextStyle(color: Colors.white),
                  ),
                  onPressed: () {
                    setState(() {
                      fields[idCounter] = NewTextField(
                        name: 'name_${idCounter}',
                        id: idCounter,
                        onDelete: (int id) {
                          setState(() {
                            fields.remove(id);
                            _formKey.currentState!.save();
                            print("Removed field #$id - current form state: ${_formKey.currentState!.value.toString()}");
                            savedValue =
                          "Removed field #$id - current form state: ${_formKey.currentState!.value.toString()}";
                          });
                        },
                      );
                      idCounter++;
                    });
                  },
                ),
              ),
            ],
          ),
          const Divider(height: 40),
          Text(savedValue),
        ],
      ),
    );
  }
}

class NewTextField extends StatelessWidget {
  const NewTextField({
    super.key,
    required this.name,
    required this.id,
    required this.onDelete,
  });
  final String name;
  final int id;
  final void Function(int) onDelete;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: Row(
        children: [
          Expanded(
            child: FormBuilderTextField(
              name: name,
              decoration: InputDecoration(
                label: Text('Field #$id'),
              ),
            ),
          ),
          IconButton(
            icon: const Icon(Icons.delete_forever),
            onPressed: () => onDelete(id),
          ),
        ],
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 07:55:56