使用TextEditingController后TextFormField的ThousandsFormatter失效如何解决
问题原因
- Flutter的
inputFormatters仅对用户键盘输入的内容生效,直接给TextEditingController.value赋值时不会触发格式化逻辑,所以你直接传入原始数值4000时,输入框就直接显示未格式化的内容。 - 你把给controller赋值的逻辑写在了
build方法中,每次页面重绘都会覆盖输入框当前值,哪怕手动输入的内容已经被格式化完成,也会立刻被原始数值覆盖,看起来就像格式化完全失效。
解决方案
步骤1:移除build方法中的controller赋值逻辑
把build方法里你写的给_textEditingController.value赋值的所有代码全部删除,避免每次重绘覆盖输入框内容。
步骤2:提取公共格式化实例
保证快捷赋值和输入框格式化用的是同一套规则,避免格式不一致:
// 放在State类内或者全局都可以,保证两处调用的是同一个实例 final _idFormatter = NumberFormat("#,###.##", "in_ID");
步骤3:监听业务控制器的数值变化,主动格式化后再赋值
仅当selectedNominal主动变更(比如点击快捷按钮)时,才把数值格式化后更新到输入框,不要频繁赋值。
在页面的State类中添加如下逻辑:
@override void initState() { super.initState(); // 监听业务控制器的数值变化 pageController.addListener(_syncTextFieldValue); // 初始同步一次数值 _syncTextFieldValue(); } void _syncTextFieldValue() { // 先把原始数值格式化 final formattedStr = _idFormatter.format(pageController.selectedNominal); // 赋值给输入框控制器,光标定位到末尾 _textEditingController.value = TextEditingValue( text: formattedStr, selection: TextSelection.collapsed(offset: formattedStr.length), ); } @override void dispose() { // 销毁前移除监听,避免内存泄漏 pageController.removeListener(_syncTextFieldValue); _textEditingController.dispose(); super.dispose(); }
步骤4:保持原有TextFormField配置不变
你原来写的ThousandsFormatter配置、onChanged逻辑不需要修改,只要保留添加的controller参数即可:
TextFormField( controller: _textEditingController, autofocus: false, autocorrect: false, maxLines: 1, textAlign: TextAlign.end, keyboardType: TextInputType.number, onChanged: (newNominal) { final newValue = newNominal.replaceAll(".", ""); controller.selectedNominal = int.tryParse(newValue) ?? 0; }, inputFormatters: [ ThousandsFormatter(formatter: _idFormatter), // 换成上面定义的公共格式化实例即可 ], ),
修改完成后,两种场景都会正常工作:
- 点击快捷按钮选择数值时,会先格式化再填入输入框,符合
4.000的展示要求 - 手动输入数值时,
ThousandsFormatter会正常触发格式化,不会再被意外覆盖
内容的提问来源于stack exchange,提问作者Agung
相关产品推荐
相关产品推荐

