[android] Decimal separator comma (',') with numberDecimal inputType in EditText

I have a solution that allows the user to enter both the dot and the comma (if available on the keyboard), but only displays the locale default separator. In addition it will not allow the user to enter more than 1 separator. No issues with references to EditText or infinite loops. It is a combination of several answers in this thread suited to my needs.

As with the accepted answer, configure the EditText accordingly:

android:inputType="numberDecimal"
android:digits="0123456789.,"

Then set a custom TextWatcher on the EditText:

myEditText.addTextChangedListener(FlexibleDecimalSeparatorTextWatcher())

And include the custom TextWatcher:

import android.text.Editable
import android.text.SpannableStringBuilder
import android.text.TextWatcher
import android.widget.EditText
import java.text.DecimalFormatSymbols

/**
 * The [FlexibleDecimalSeparatorTextWatcher] allows the user to input both the comma (,) and dot (.) as a decimal separator,
 * and will then automatically convert each entered separator into the locale default separator.
 * If the user were to enter multiple separators - every separator but the first will be removed.
 *
 * To provide comma and dot support, set the [EditText] inputType to 'numberDecimal' and its digits to '0123456789.,'.
 */
class FlexibleDecimalSeparatorTextWatcher : TextWatcher {
companion object {
    private val DECIMAL_SEPARATORS = listOf('.', ',')
    private val LOCALE_DEFAULT_DECIMAL_SEPARATOR = DecimalFormatSymbols.getInstance().decimalSeparator
}

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 != null) {
        val textWithConvertedSeparators = convertSeparatorsToLocaleDefault(s.toString())
        val textWithoutMultipleSeparators = removeAdditionalSeparators(textWithConvertedSeparators)

        // Make the change if required. This only triggers one additional afterTextChanged call if there were changes.
        if(s.toString() != textWithoutMultipleSeparators) {
            s.replace(0, s.length, SpannableStringBuilder(textWithoutMultipleSeparators))
        }
    }
}

/**
 * This function converts all entered separators (in [DECIMAL_SEPARATORS]) to the [LOCALE_DEFAULT_DECIMAL_SEPARATOR].
 */
private fun convertSeparatorsToLocaleDefault(original: String): String {
    var result = original
    DECIMAL_SEPARATORS.forEach { separator ->
        if (separator != LOCALE_DEFAULT_DECIMAL_SEPARATOR && result.contains(separator)) {
            result = result.replace(separator, LOCALE_DEFAULT_DECIMAL_SEPARATOR)
        }
    }
    return result
}

/**
 * Strip out all separators but the first.
 * In this function we assume all separators are already converted to the locale default.
 */
private fun removeAdditionalSeparators(original: String): String {
    var result = original
    var separatorCount = result.count { c -> c == LOCALE_DEFAULT_DECIMAL_SEPARATOR }
    if(separatorCount > 1) {
        // We will reverse the text so we can keep stripping the last (first in reverse) separator off.
        var textReversed = result.reversed()
        val separatorRegex = Regex.fromLiteral(LOCALE_DEFAULT_DECIMAL_SEPARATOR.toString())
        while (separatorCount > 1) {
            textReversed = textReversed.replaceFirst(separatorRegex, "")
            separatorCount--
        }
        // And finally we reverse it back to the original order.
        result = textReversed.reversed()
    }
    return result
}

}

Examples related to android

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How to implement a simple scenario the OO way My eclipse won't open, i download the bundle pack it keeps saying error log getting " (1) no such column: _id10 " error java doesn't run if structure inside of onclick listener Cannot retrieve string(s) from preferences (settings) strange error in my Animation Drawable how to put image in a bundle and pass it to another activity FragmentActivity to Fragment A failure occurred while executing com.android.build.gradle.internal.tasks

Examples related to android-edittext

This view is not constrained vertically. At runtime it will jump to the left unless you add a vertical constraint Design Android EditText to show error message as described by google Change EditText hint color when using TextInputLayout How to change the floating label color of TextInputLayout The specified child already has a parent. You must call removeView() on the child's parent first (Android) Edittext change border color with shape.xml Changing EditText bottom line color with appcompat v7 Soft keyboard open and close listener in an activity in Android EditText underline below text property Custom designing EditText

Examples related to decimal-point

Round to at most 2 decimal places (only if necessary) Int to Decimal Conversion - Insert decimal point at specified location Integer.valueOf() vs. Integer.parseInt() How to change the decimal separator of DecimalFormat from comma to dot/point? Decimal separator comma (',') with numberDecimal inputType in EditText How to print a float with 2 decimal places in Java? Javascript: formatting a rounded number to N decimals Formatting a number with exactly two decimals in JavaScript Leave only two decimal places after the dot In jQuery, what's the best way of formatting a number to 2 decimal places?