Flutter TextField两位小数输入限制异常:超位输入无显示但可退格删除求助
解决Flutter TextField两位小数输入后无效字符残留问题
问题根源
- 原正则表达式
r'^\d+\.?\,?\d{0,2}'逻辑错误:允许同时出现小数点和逗号,且未限制小数分隔符的数量,输入校验不严谨。 - 使用
FilteringTextInputFormatter.allow仅过滤不匹配字符,但无效输入会留在输入缓冲区,退格时需先删除这些不可见的无效内容。 onChanged仅更新变量未同步控制器文本,导致显示内容与实际输入缓冲区不一致。
解决方案
替换原输入格式化器为自定义的TextInputFormatter,严格控制输入格式,同时修正onChanged和onSubmitted的逻辑:
1. 定义自定义输入格式化器
class TwoDecimalInputFormatter extends TextInputFormatter { @override TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { // 允许空输入 if (newValue.text.isEmpty) return newValue; // 匹配规则:可选负号 + 整数部分 + 可选小数点 + 0-2位小数 final regex = RegExp(r'^-?\d*\.?\d{0,2}$'); if (!regex.hasMatch(newValue.text)) { // 不匹配则返回旧值,拒绝无效输入 return oldValue; } // 处理单独输入小数点的情况,自动补0 if (newValue.text == '.') { return TextEditingValue( text: '0.', selection: TextSelection.collapsed(offset: 2), ); } // 处理负号后直接输入小数点的情况 if (newValue.text.startsWith('-.') && newValue.text.length == 2) { return TextEditingValue( text: '-0.', selection: TextSelection.collapsed(offset: 3), ); } return newValue; } }
2. 修改TextField代码
TextField( controller: extraAmountController, inputFormatters: [TwoDecimalInputFormatter()], // 使用自定义格式化器 keyboardType: TextInputType.numberWithOptions(decimal: true, signed: true), onChanged: (amount) { if (amount.isEmpty) { extraAmount = "0.00"; } else if (amount.endsWith('.')) { // 处理末尾是小数点的情况,转为两位小数格式 extraAmount = double.parse(amount.replaceAll('.', '')).toStringAsFixed(2); } else { extraAmount = double.parse(amount).toStringAsFixed(2); } print(extraAmount); }, onSubmitted: (amount) { if (amount.isEmpty) { extraAmountController.text = extraAmount = "0.00"; } else if (amount.endsWith('.')) { extraAmount = double.parse(amount.replaceAll('.', '')).toStringAsFixed(2); extraAmountController.text = extraAmount; } else { extraAmount = double.parse(amount).toStringAsFixed(2); extraAmountController.text = extraAmount; } print(extraAmount); }, textAlignVertical: TextAlignVertical.center, cursorColor: Colors.black45, decoration: InputDecoration( hintText: usersList.first.extraAmount, contentPadding: const EdgeInsets.only(left: 10), suffixIcon: Icon(Icons.business_center, color: Colors.grey), border: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey), ), disabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5), borderSide: BorderSide(color: Colors.grey), ), ), )
说明
自定义格式化器会直接拒绝不符合规则的输入,不会让无效内容进入输入缓冲区,彻底解决退格时需删除不可见内容的问题。同时优化了空输入、末尾小数点等边界情况的处理,保证输入格式始终符合两位小数的要求。
内容的提问来源于stack exchange,提问作者Flutter
相关产品推荐
相关产品推荐

