Способы автоформатирования текста, введенного в EditText в Kotlin Android
Мне нужно, чтобы, когда я вводил денежные суммы, то текст сразу бы форматировался в нужный мне денежный формат. Например, ввел 1000 - в editText сразу текст отображался бы как 1 000; 10000 -> 10 000; 100000 -> 100 000. При этом можно вводить не только целые значения, т.е. пользователь может ввести 10003.034 и в этом случае число должно отобразиться как 10 003,034. Локали 2: En/Rus. Есть ли относительно простой способ сделать такое? Или нужно с нуля свое кастомное вью с логикой писать? Уже много разных решений испробовал, но как правило все заканчивается крашами приложения после первого форматирования или попытке стереть текст, либо поддерживается ввод лишь целых чисел)
editText.addTextChangedListener(object : TextWatcher {
var current = ""
override fun afterTextChanged(salary: Editable?) {
/* формат */
if (salary.toString() != current) {
editText.removeTextChangedListener(this)
val formatter = DecimalFormat()
val symbols = DecimalFormatSymbols.getInstance()
symbols.groupingSeparator = ' '
formatter.decimalFormatSymbols = symbols
val newValue = formatter.format(salary.toString().toBigDecimal()).toString()
current = newValue
editText.setText(newValue)
editText.setSelection(newValue.length)
editText.addTextChangedListener(this)
}
}
override fun beforeTextChanged(salary: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(salary: CharSequence?, start: Int, before: Int, count: Int) {
}
})
Ответы (1 шт):
Ваш код неверен в том, что меняет текст напрямую в контроле и из-за этого вынужден переподписываться. Все проще.
Вот рабочий код для целых сумм с лимитом на разрядность для локали ru-RU.
Лимит можно убрать и переделать для десятичных и нескольких локалей.
class AmountTextWatcher(val limit: Int) : TextWatcher {
private val formatter = NumberFormat.getIntegerInstance(Locale.forLanguageTag("ru-RU"))
val delimiter = formatter.format(1000)[1].toString()
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
if (s.isNotBlank()) {
val num = try { formatter.parse(s.toString().take(limit)) } catch (ex: ParseException) { null }
val numStr = num?.let { formatter.format(num) } ?: ""
if (s.toString() != numStr) {
s.replace(0, s.length, numStr)
}
}
}
}