如何在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
相关产品推荐
相关产品推荐

