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 }
关键修改点说明
- 光标位置处理:格式化前记录光标位置,计算格式化后的光标偏移量,避免用户输入时光标跳转到文本开头,提升交互体验。
- 小数位数限制:通过分割字符串并截取前两位小数,强制限制小数部分最多两位,符合需求。
- 分隔符冲突处理:当用户同时输入
.和,时,保留最后出现的那个作为小数分隔符,避免格式混乱。 - 边界情况处理:处理空输入、纯小数输入等边界场景,避免
NumberFormatException。 - 格式化符号配置:明确指定
groupingSeparator为.(千分位),decimalSeparator为,(小数位),配合#,##0.##模式实现正确的格式输出。
内容的提问来源于stack exchange,提问作者Berkay
相关产品推荐
相关产品推荐

