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

如何使用TextWatcher实现EditText从右到左的金额自动格式化?

实现PayPal风格的EditText自动小数格式化

这个需求我之前做支付类应用时正好遇到过,用TextWatcher完全能搞定核心逻辑——把用户输入的每一位数字当作分来处理,自动转换成保留两位小数的“元”格式,完美匹配你要的效果。

核心思路

用户输入的数字序列其实是总分数:

  • 输入1 → 1分 → 0.01元
  • 输入11 → 11分 → 0.11元
  • 输入222 → 222分 → 2.22元

为了避免setText触发TextWatcher的循环调用,我们需要加一个状态标志位;同时维护一个纯数字字符串来跟踪用户的真实输入(避免从格式化后的带小数点文本里提取数字的麻烦)。

完整代码实现

替换你现有的EditTextListener,用下面的版本:

private class EditTextListener implements TextWatcher {
    // 保存用户输入的纯数字序列
    private String currentDigits = "";
    // 防止setText触发循环更新的标志位
    private boolean isUpdating = false;
    // 确保输出格式始终是两位小数
    private final DecimalFormat decimalFormat = new DecimalFormat("0.00");

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // 不需要额外处理
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (isUpdating) return;

        // 处理用户输入字符:追加纯数字到currentDigits
        if (count > 0) {
            String input = s.subSequence(start, start + count).toString();
            // 过滤掉非数字字符(防止意外输入)
            input = input.replaceAll("[^0-9]", "");
            currentDigits += input;
        }
        // 处理用户删除字符:从currentDigits末尾截断
        else if (before > 0) {
            if (currentDigits.length() >= before) {
                currentDigits = currentDigits.substring(0, currentDigits.length() - before);
            } else {
                currentDigits = "";
            }
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
        if (isUpdating) return;
        isUpdating = true;

        if (currentDigits.isEmpty()) {
            // 无输入时重置为默认的0.00
            editText.setText("0.00");
            // 光标定位到小数点前,方便继续输入
            editText.setSelection(1);
        } else {
            try {
                // 将数字转为分,再除以100得到元
                long cents = Long.parseLong(currentDigits);
                BigDecimal amount = BigDecimal.valueOf(cents).divide(BigDecimal.valueOf(100));
                String formattedText = decimalFormat.format(amount);
                editText.setText(formattedText);
                // 光标固定在小数点前的数字末尾,保持输入流畅性
                int cursorPos = formattedText.indexOf(".") - 1;
                editText.setSelection(Math.max(cursorPos, 0));
            } catch (NumberFormatException e) {
                // 处理数字过大溢出的情况,重置为默认值
                editText.setText("0.00");
                currentDigits = "";
                editText.setSelection(1);
            }
        }

        isUpdating = false;
    }
}

额外优化建议

  1. XML输入类型限制:为EditText设置inputType="number",让系统弹出纯数字键盘,避免用户输入非数字字符:
<EditText
    android:id="@+id/editText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:inputType="number"
    android:text="0.00" />
  1. 大数处理:如果需要支持超过Long范围的数字(比如超长金额),可以把Long.parseLong换成BigInteger来处理:
BigInteger cents = new BigInteger(currentDigits);
BigDecimal amount = new BigDecimal(cents).divide(BigDecimal.valueOf(100));

效果验证

  • 初始状态:显示0.00,光标在0和.之间
  • 输入1 → 显示0.01
  • 再输入1 → 显示0.11
  • 再输入2 → 显示1.12
  • 删除一次 → 回到0.11
  • 删除至空 → 重置为0.00

内容的提问来源于stack exchange,提问作者Félix Maroy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:57:48