如何使用TextEditingController在TextField中格式化数字为货币格式
实时格式化TextField为货币形式的解决方案
你的代码无效的核心原因是:NumberFormat.format()方法需要接收**数字类型(num)**作为参数,但你直接传入了字符串类型的contractPriceController.text,导致格式化逻辑无法生效。下面是可行的实现方案,包含输入过滤、数字格式化和光标位置处理:
步骤1:初始化格式化器和控制器
使用NumberFormat.currency创建标准的货币格式化器,同时初始化TextEditingController:
final NumberFormat currencyFormatter = NumberFormat.currency( locale: 'en_US', symbol: '\$', // 可根据需求修改货币符号 decimalDigits: 2, // 设置保留的小数位数 ); final TextEditingController contractPriceController = TextEditingController();
步骤2:实现实时格式化逻辑
在onChanged回调中,先过滤无效输入字符,再转换为数字进行格式化,同时修正光标位置避免输入体验混乱:
TextField( keyboardType: TextInputType.numberWithOptions(decimal: true), controller: contractPriceController, textAlign: TextAlign.center, inputFormatters: [ // 限制仅能输入数字和一个小数点 FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')), ], onChanged: (value) { // 过滤掉非数字和多余小数点,提取有效数字字符串 String cleanValue = value.replaceAll(RegExp(r'[^\d.]'), ''); if (cleanValue.split('.').length > 2) { cleanValue = cleanValue.substring(0, cleanValue.lastIndexOf('.')); } if (cleanValue.isNotEmpty) { // 转换为数字并格式化 num number = num.parse(cleanValue); String formattedValue = currencyFormatter.format(number); // 计算光标偏移量,保证光标始终在输入位置后方 int cursorPosition = contractPriceController.selection.end; int offset = formattedValue.length - value.length; // 更新控制器文本与光标位置 contractPriceController.value = contractPriceController.value.copyWith( text: formattedValue, selection: TextSelection.collapsed(offset: cursorPosition + offset), ); } else { contractPriceController.clear(); } }, decoration: const InputDecoration( hintText: 'Contract Price', labelText: 'Contract Price', ), )
关键细节说明
- 输入过滤:通过
FilteringTextInputFormatter和正则表达式,避免用户输入非数字、多个小数点等无效内容,减少格式化逻辑的异常风险。 - 光标位置处理:格式化后文本长度会因添加千位分隔符、货币符号而变化,必须计算偏移量修正光标位置,保证输入流畅。
- 格式化器选择:
NumberFormat.currency比自定义格式更规范,自动适配指定地区的货币显示规则。
内容的提问来源于stack exchange,提问作者LostTexan
相关产品推荐
相关产品推荐

