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

Kotlin实现EditText数字千分位与两位小数格式化(点分千位逗号分小数)

实现符合需求的EditText数值格式化TextWatcher

需求回顾

  • 整数部分每三位用.作为千分分隔符,如输入10000显示为10.000
  • 小数部分用,作为分隔符,最多允许两位小数,如输入1000050显示为10.000,50
  • 支持用户输入逗号或点时自动转换为正确格式

修改后的完整代码

et_cekme_tutari.addTextChangedListener(object : TextWatcher {
    override fun afterTextChanged(editable: Editable?) {
        et_cekme_tutari.removeTextChangedListener(this)
        try {
            editable ?: return
            val originalText = editable.toString()
            var cleanText = originalText

            // 移除所有千分位分隔符(.)
            cleanText = cleanText.replace(thousandSeparator.toString(), "")

            // 处理同时包含,和.的情况:只保留最后出现的那个作为小数分隔符
            val dotIndex = cleanText.indexOf('.')
            val commaIndex = cleanText.indexOf(',')
            if (dotIndex != -1 && commaIndex != -1) {
                // 保留靠后的那个作为小数分隔符,移除另一个
                val keepSeparator = if (dotIndex > commaIndex) '.' else ','
                cleanText = cleanText.replace(if (keepSeparator == '.') ',' else '.', "")
            }

            // 将所有小数分隔符统一转换为.(方便后续转Double)
            cleanText = cleanText.replace(',', '.')

            // 限制小数部分最多两位
            val decimalSplit = cleanText.split('.')
            if (decimalSplit.size > 2) {
                // 超过一个小数点,取前两个部分并截断小数位到两位
                cleanText = "${decimalSplit[0]}.${decimalSplit[1].take(2)}"
            } else if (decimalSplit.size == 2) {
                // 小数部分截断到两位
                cleanText = "${decimalSplit[0]}.${decimalSplit[1].take(2)}"
            }

            // 转换为数值(空或纯小数时处理边界)
            val doubleVal = if (cleanText.isEmpty() || cleanText == ".") {
                0.0
            } else {
                cleanText.toDouble()
            }

            // 配置格式化符号:千分位用.,小数用,
            val formatSymbols = DecimalFormatSymbols()
            formatSymbols.groupingSeparator = thousandSeparator // .
            formatSymbols.decimalSeparator = decimalSeparator // ,

            // 格式化模式:整数部分至少1位,千分分隔,小数部分最多两位(可选)
            val formatter = DecimalFormat("#,##0.##", formatSymbols)
            formatter.groupingSize = 3
            var formattedString = formatter.format(doubleVal)

            // 处理纯整数时,避免显示多余的小数分隔符(比如10.000, 这种情况)
            if (!originalText.contains(decimalSeparator) && decimalSplit.size == 1) {
                formattedString = formattedString.replace(",", "")
            }

            // 保存并恢复光标位置,避免格式化后光标跳到开头
            val cursorPosition = et_cekme_tutari.selectionStart
            val cursorOffset = formattedString.length - (originalText.length - cursorPosition)
            et_cekme_tutari.setText(formattedString)
            // 确保光标位置合法
            val finalCursor = if (cursorOffset >= 0 && cursorOffset <= formattedString.length) cursorOffset else formattedString.length
            et_cekme_tutari.setSelection(finalCursor)

        } catch (nfe: NumberFormatException) {
            nfe.printStackTrace()
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            et_cekme_tutari.addTextChangedListener(this)
        }
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})

private var decimalSeparator: Char = ','
private var thousandSeparator: Char = '.'

fun setDecimalSeparator(decimalSeparator: Char) {
    this.decimalSeparator = decimalSeparator
}

fun setThousandSeparator(thousandSeparator: Char) {
    this.thousandSeparator = thousandSeparator
}

关键修改点说明

  1. 光标位置处理:格式化前记录光标位置,计算格式化后的光标偏移量,避免用户输入时光标跳转到文本开头,提升交互体验。
  2. 小数位数限制:通过分割字符串并截取前两位小数,强制限制小数部分最多两位,符合需求。
  3. 分隔符冲突处理:当用户同时输入.和,时,保留最后出现的那个作为小数分隔符,避免格式混乱。
  4. 边界情况处理:处理空输入、纯小数输入等边界场景,避免NumberFormatException。
  5. 格式化符号配置:明确指定groupingSeparator为.(千分位),decimalSeparator为,(小数位),配合#,##0.##模式实现正确的格式输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 05:25:45