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

如何在Dart和Flutter中通过输入自动动态生成文本字段?

动态文本字段优化需求

我能通过点击图标和按钮实现动态文本字段,但无法通过输入触发。之前获取的一段代码可正常运行,但新增字段需按Ctrl+S触发:

final List<TextEditingController> _controllers = [];
ListView.builder(
        itemCount: _controllers.length + 1,
        itemBuilder: (context, index) {
          if (index == _controllers.length) {
            // 到达列表末尾时返回新文本字段
            final controller = TextEditingController();
            _controllers.add(controller);
            return Padding(
              padding: const EdgeInsets.all(20),
              child: TextField(
                controller: controller,
                decoration: const InputDecoration(
                  hintText: 'Enter text here',
                ),
              ),
            );
          } else {
            // 返回已存在的文本字段
            return Padding(
              padding: const EdgeInsets.all(20),
              child: TextField(
                controller: controllers[index],
                decoration: const InputDecoration(
                  hintText: 'Enter text here',
                ),
              ),
            );
          }
        },
      ),

我的实现代码:

ListView.builder(
                    itemCount: dynamicTextFeild.length,
                    itemBuilder: (context, index) {
                      if (controller.selection == true) {
                        dynamicTextFeild.add(
                          DynamicTextFeild(
                            labelIndex: dynamicTextFeild.length,
                            controller: controller,
                          ),
                        );
                        return DynamicTextFeild(
                          labelIndex: dynamicTextFeild.length,
                          controller: controller,
                        );
                      }
                      return null;
                    },
                  ),

核心需求:在文本字段输入内容后,自动生成包含分类和文本字段的DynamicTextFeild组件。

DynamicTextFeild组件代码:

class DynamicTextFeild extends StatefulWidget {
  int labelIndex;
  final TextEditingController controller;
  DynamicTextFeild({
    Key? key,
    required this.labelIndex,
    required this.controller,
  }) : super(key: key);

  @override
  State<DynamicTextFeild> createState() => _DynamicTextFeildState();
}

class _DynamicTextFeildState extends State<DynamicTextFeild> {
  String generiteLabel(int labelIndex) {
    if (labelIndex == 0) {
      return "phone...";
    } else if (labelIndex == 1) {
      return "phone...";
    } else if (labelIndex == 2) {
      return "phone...";
    } else if (labelIndex == 3) {
      return "phone...";
    } else if (labelIndex == 4) {
      return "phone...";
    } else if (labelIndex == 5) {
      return "phone...";
    } else if (labelIndex == 6) {
      return "phone...";
    } else if (labelIndex == 7) {
      return "phone...";
    } else if (labelIndex == 8) {
      return "phone...";
    } else if (labelIndex == 9) {
      return "phone...";
    } else if (labelIndex == 10) {
      return "phone...";
    } else {
      return generiteLabel.toString();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Expanded(flex: 1, child: Category()),
        Expanded(
          flex: 2,
          child: TFF(
            controller: widget.controller,
            label: "phone...",
            left: 5.0,
            keyboardType: TextInputType.phone,
          ),
        ),
      ],
    );
  }
}

目前已实现输入生成文本字段,但每次都需手动为DynamicTextFeild配置onChange,存在使用局限,求优化建议。

当前手动配置onChange的代码:

DynamicTextFeild(
            controller: controller,
            onChange: (p0) {
              String p0 = "";
              List<String> words = p0.split(" ");
              String firstWord = words[0];
              if (dynamicTextFeild.length == firstWord.length) {
                print(dynamicTextFeild.length);
                setState(
                  () {
                    dynamicTextFeild.add(
                      DynamicTextFeild(
                        lableIndex: labelIndex,
                        controller: TextEditingController(),
                        onChange: (Value) {
                          print(dynamicTextFeild.length);
                          if (Value.length == 1) {
                            setState(
                              () {
                                dynamicTextFeild.add(
                                  DynamicTextFeild(
                                    lableIndex: labelIndex,
                                    controller: TextEditingController(),
                                  ),
                                );
                              },
                            );
                          }
                        },
                      ),
                    );
                  },
                );
                print(dynamicTextFeild.length);
              }
            },
            lableIndex: labelIndex,
          ),
          SizedBox(
            width: Get.width,
            height: 400,
            child: Column(
              children: dynamicTextFeild,
            ),
          ),

优化方案

1. 让DynamicTextFeild内置输入监听逻辑

修改组件,添加回调函数通知父组件新增字段,内部监听输入变化,满足条件时自动触发回调,无需手动配置onChange:

class DynamicTextFeild extends StatefulWidget {
  int labelIndex;
  final TextEditingController controller;
  final VoidCallback? onNeedAddField; // 新增回调,通知父组件添加字段

  DynamicTextFeild({
    Key? key,
    required this.labelIndex,
    required this.controller,
    this.onNeedAddField,
  }) : super(key: key);

  @override
  State<DynamicTextFeild> createState() => _DynamicTextFeildState();
}

class _DynamicTextFeildState extends State<DynamicTextFeild> {
  String generiteLabel(int labelIndex) {
    // 简化原if-else逻辑
    List<String> labels = List.filled(11, "phone...");
    return labelIndex < labels.length ? labels[labelIndex] : labelIndex.toString();
  }

  @override
  void initState() {
    super.initState();
    // 监听输入变化
    widget.controller.addListener(_onInputChanged);
  }

  void _onInputChanged() {
    String input = widget.controller.text;
    // 这里替换成你的触发条件,示例为输入长度达到1时触发
    if (input.length == 1 && widget.onNeedAddField != null) {
      widget.onNeedAddField!();
      // 可选:移除当前监听,避免重复触发
      widget.controller.removeListener(_onInputChanged);
    }
  }

  @override
  void dispose() {
    widget.controller.removeListener(_onInputChanged);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        const Expanded(flex: 1, child: Category()),
        Expanded(
          flex: 2,
          child: TFF(
            controller: widget.controller,
            label: generiteLabel(widget.labelIndex), // 使用生成的label
            left: 5.0,
            keyboardType: TextInputType.phone,
          ),
        ),
      ],
    );
  }
}

2. 父组件统一管理字段列表

父组件只需维护字段列表,新增字段时统一添加带回调的DynamicTextFeild,无需重复编写onChange逻辑:

// 父组件代码
List<DynamicTextFeild> dynamicTextFeild = [];
// 建议额外维护控制器列表,方便后续销毁释放内存
List<TextEditingController> _controllers = [];

@override
void initState() {
  super.initState();
  // 初始化第一个字段
  _addNewField();
}

void _addNewField() {
  int newIndex = dynamicTextFeild.length;
  TextEditingController newController = TextEditingController();
  _controllers.add(newController);
  
  dynamicTextFeild.add(
    DynamicTextFeild(
      labelIndex: newIndex,
      controller: newController,
      onNeedAddField: () {
        setState(() {
          _addNewField();
        });
      },
    ),
  );
}

@override
void dispose() {
  // 销毁所有控制器,避免内存泄漏
  for(var controller in _controllers) {
    controller.dispose();
  }
  super.dispose();
}

@override
Widget build(BuildContext context) {
  return SizedBox(
    width: Get.width,
    height: 400,
    child: Column(
      children: dynamicTextFeild,
    ),
  );
}

3. 额外优化点

  • 可根据实际需求调整_onInputChanged中的触发条件,比如检测输入是否符合特定格式、是否非空等;
  • 如果需要支持删除字段,可在DynamicTextFeild中添加删除按钮和对应的回调,父组件同步维护列表和控制器;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:07:03