You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter支付金额TextField:千分位分隔及小数两位限制问题

Flutter TextField 实现千分位分隔+小数点后两位限制(解决多格式化器冲突问题)

解决方案

1. 修改千分位格式化器,兼容小数处理

原格式化器仅处理整数部分,未考虑小数点逻辑,且无法和其他格式化器兼容。调整后可同时处理整数千分位分隔和小数位限制:

class ThousandsSeparatorInputFormatter extends TextInputFormatter {
  static const separator = ',';

  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    // 空值直接返回
    if (newValue.text.isEmpty) {
      return newValue.copyWith(text: '');
    }

    // 移除已有分隔符,分离整数和小数部分
    String cleanValue = newValue.text.replaceAll(separator, '');
    List<String> valueParts = cleanValue.split('.');
    
    // 限制小数部分最多两位
    if (valueParts.length > 1) {
      if (valueParts[1].length > 2) {
        valueParts[1] = valueParts[1].substring(0, 2);
      }
    }

    // 处理整数部分的千分位分隔
    String integerPart = valueParts[0];
    String formattedInteger = '';
    for (int i = integerPart.length - 1; i >= 0; i--) {
      if ((integerPart.length - 1 - i) % 3 == 0 && i != integerPart.length - 1) {
        formattedInteger = separator + formattedInteger;
      }
      formattedInteger = integerPart[i] + formattedInteger;
    }

    // 拼接整数与小数部分
    String formattedText = formattedInteger;
    if (valueParts.length > 1 && valueParts[1].isNotEmpty) {
      formattedText += '.${valueParts[1]}';
    }

    // 计算光标位置,避免因分隔符添加/删除导致错位
    int originalCursorPos = newValue.selection.end;
    int newSeparatorCount = formattedText.substring(0, originalCursorPos).split(separator).length - 1;
    int oldSeparatorCount = newValue.text.substring(0, originalCursorPos).split(separator).length - 1;
    int adjustedCursorPos = originalCursorPos + (newSeparatorCount - oldSeparatorCount);
    adjustedCursorPos = adjustedCursorPos.clamp(0, formattedText.length);

    return TextEditingValue(
      text: formattedText,
      selection: TextSelection.collapsed(offset: adjustedCursorPos),
    );
  }
}

2. 正确配置TextField的inputFormatters

格式化器执行顺序至关重要,需先过滤非法输入,再应用千分位格式化:

TextField(
  keyboardType: TextInputType.numberWithOptions(decimal: true),
  controller: controller,
  inputFormatters: [
    // 仅允许输入数字和小数点,同时限制小数位最多两位
    FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')),
    // 千分位格式化器放在最后,基于合法输入处理分隔符
    ThousandsSeparatorInputFormatter(),
  ],
  decoration: InputDecoration(
    labelText: '支付金额',
  ),
)

核心注意点

  • 顺序优先级:先通过过滤规则确保输入合法,再执行千分位格式化,避免非法字符干扰分隔逻辑。
  • 光标适配:格式化器内计算光标偏移量,保证输入/删除操作时光标位置正确。
  • 小数限制:在格式化器内直接处理小数位截断,配合过滤规则双重保障输入合规。

内容的提问来源于stack exchange,提问作者user22362195

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 19:58:34