Kotlin实现货币金额右对齐输入格式化异常排查及方案咨询
现有代码逻辑错误点
- 退格逻辑完全错误:一方面
text.drop(1)是删除字符串首字符,和退格需要删除末尾输入内容的需求完全相反;另一方面代码最后无条件把显示文本设为空,等于前面的删除操作完全无效,退格会直接清空所有内容。 - 金额换算逻辑完全不符合需求:需要的从右向左填零效果,本质是所有输入的数字默认按「分」(货币最小单位)存储,满2位才进位到「元」。但现有代码把格式化后文本里提取出的所有数字直接当做「元」为单位的值转double,比如输入1、2两个数字,提取出12直接按12元格式化成$12.00,完全没有做分到元的除以100换算,必然出现数值量级错误。
- 数据源设计不合理:直接拿已经格式化过的显示文本作为输入拼接的数据源,货币格式自带的$、千分位逗号、小数点都会干扰数字提取,很容易出现提取出的数字串长度异常,这也是出现$1,0002.00这种格式错误的直接原因——格式化后的文本带千分位逗号,提取数字时会把逗号位置的数字拼接错位。比如输入1后显示$1.00,此时提取数字是"100",再输入0拼接后是"1000",转成1000.0格式化出$1,000.00,再输入2,提取显示文本里的数字加新输入的2变成"10002",转值格式化时就会出现千分位错位的异常结果。
更优实现方案
核心思路是不要依赖UI显示文本做数据存储,单独维护纯数字的输入缓存,所有输入、退格操作只修改这个缓存,最后统一做单位换算和格式化,从根源避免格式字符干扰。
具体实现代码:
首先在页面类里定义全局的输入缓存,单位为分:
// 存储所有输入的纯数字,单位为货币最小单位(分) private val inputCentBuilder = StringBuilder()
修改数字输入回调,只往缓存里追加数字,限制最大输入长度避免数值溢出:
binding.keypad.onNumberSelected = { num -> // 最多支持9位数字,即最高9999999.99元,可根据业务调整 if (inputCentBuilder.length < 9) { inputCentBuilder.append(num) updateAmountDisplay() } }
修改退格键逻辑,只删除缓存的最后一位:
binding.keypad.btnBackspace.setOnClickListener { if (inputCentBuilder.isNotEmpty()) { inputCentBuilder.deleteCharAt(inputCentBuilder.lastIndex) updateAmountDisplay() } }
实现统一的显示刷新方法,做单位换算后格式化:
private fun updateAmountDisplay() { val centValue = if (inputCentBuilder.isEmpty()) { 0L } else { inputCentBuilder.toString().toLong() } // 分转元,用BigDecimal避免double浮点精度问题 val yuanValue = BigDecimal.valueOf(centValue) .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_EVEN) binding.tvTotalValue.text = NumberFormat.getCurrencyInstance().format(yuanValue) }
按上述实现验证交互:
- 依次按1、2:缓存值为
12→ 12分 → 0.12元 → 显示$0.12 - 再按3:缓存值为
123→123分→1.23元→显示$1.23 - 按退格:删掉缓存最后一位3,回到
12→显示$0.12,完全符合预期。
内容的提问来源于stack exchange,提问作者user-44651
相关产品推荐
相关产品推荐

