Flutter TextField数字逗号格式化:小数输入与长度计数问题求助
Flutter TextField数字格式化解决方案
针对你遇到的两个核心问题:无法支持小数输入、逗号计入maxLength计数,以下是修改后的完整实现:
1. 改进的ThousandsFormatter(支持小数格式化)
import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; class ThousandsFormatter extends TextInputFormatter { @override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { final rawText = newValue.text.replaceAll(',', ''); // 空值直接返回 if (rawText.isEmpty) { return const TextEditingValue(text: ''); } // 拆分整数与小数部分,限制小数最多两位 String integerPart; String decimalPart = ''; if (rawText.contains('.')) { final parts = rawText.split('.'); integerPart = parts[0]; decimalPart = parts.length > 1 ? parts[1].substring(0, parts[1].length > 2 ? 2 : parts[1].length) : ''; } else { integerPart = rawText; } // 格式化整数部分为千分位格式 final formattedInteger = NumberFormat('#,##,##,###').format(int.tryParse(integerPart) ?? 0); // 拼接最终格式化文本 final formattedText = decimalPart.isNotEmpty ? '$formattedInteger.$decimalPart' : formattedInteger; // 计算光标偏移位置,避免格式化后光标错位 int selectionOffset = newValue.selection.end; if (rawText.contains('.') && newValue.selection.end > rawText.indexOf('.')) { // 光标在小数点后时,直接映射到格式化文本的对应位置 selectionOffset = formattedText.length - (rawText.length - newValue.selection.end); } else { // 光标在整数部分时,根据新增的逗号数量调整偏移 final commaCountAdded = formattedText.length - rawText.length; selectionOffset += commaCountAdded; } return TextEditingValue( text: formattedText, selection: TextSelection.collapsed(offset: selectionOffset.clamp(0, formattedText.length)), ); } }
2. 自定义长度限制Formatter(忽略逗号计数)
系统默认的LengthLimitingTextInputFormatter会把逗号算入长度配额,我们自定义一个只统计有效字符(数字+小数点)的限制器:
class CustomLengthLimitingFormatter extends TextInputFormatter { final int maxLength; CustomLengthLimitingFormatter(this.maxLength); @override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { final rawText = newValue.text.replaceAll(',', ''); if (rawText.length > maxLength) { // 截断超出长度的有效字符,再重新格式化 final truncatedRaw = rawText.substring(0, maxLength); return ThousandsFormatter().formatEditUpdate(oldValue, TextEditingValue(text: truncatedRaw)); } return newValue; } }
3. TextField的正确配置
调整inputFormatters的顺序,确保先过滤非法字符、再限制长度、最后应用格式化:
TextField( onEditingComplete: () { FocusScope.of(context).requestFocus(_focusNodeY); }, controller: principalController, decoration: const InputDecoration( labelText: "金额", isDense: true, counterText: "", ), textAlign: TextAlign.start, maxLines: 1, keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ // 只允许输入数字和小数点 FilteringTextInputFormatter.allow(RegExp(r'^[0-9]+(\.[0-9]{0,2})?$')), // 限制有效字符长度(比如支持8位整数+2位小数,这里设为10) CustomLengthLimitingFormatter(10), // 最后应用千分位格式化 ThousandsFormatter(), ], )
关键说明
- 小数处理:拆分整数与小数部分分别处理,自动截断超出两位的小数,输入过程中实时保持格式
- 光标定位:针对小数点前后的光标位置做了适配,避免格式化后光标跳至错误位置
- 长度限制:自定义的长度限制器仅统计数字和小数点的长度,逗号不占用
maxLength配额,无需因格式符号额外调整长度值
内容的提问来源于stack exchange,提问作者ocean
相关产品推荐
相关产品推荐

