RediOne1
RediOne1

Reputation: 10729

Decimal separator key not visible when DigitsKeyListener is set

I want to allow the user to enter numbers with a decimal separator (comma or dot) depending on the region.

Now I'm using DigitsKeyListener to enable comma as separator for some locales (e.g. Poland, Germany).

val separator = DecimalFormatSymbols.getInstance().decimalSeparator
editTextValue.keyListener = DigitsKeyListener.getInstance("-0123456789$separator")

This code is written in .

If software keyboard is Gboard or other third party keyboard, then everything is fine and user can use comma or dot as separator.

But when user use stock keyboard and DigitsKeyListener is set, then not all keys are visible and user is not able to add separator.

This is my EditText code:

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInput"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    app:hintTextAppearance="@style/Lorin.Theme.TextInputLayout"
    app:layout_constraintLeft_toRightOf="@id/imageInfo"
    app:layout_constraintRight_toLeftOf="@id/buttonHistoryNumeric">

    <android.support.design.widget.TextInputEditText
        android:id="@+id/editTextValue"
        style="@style/Lorin.EditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:imeOptions="flagNavigateNext"
        android:inputType="number|numberSigned|numberDecimal"
        android:maxLines="1"
        tools:hint="Range"/>
</android.support.design.widget.TextInputLayout>

Keyboard without separator key


val separator = DecimalFormatSymbols.getInstance().decimalSeparator
//editTextValue.keyListener = DigitsKeyListener.getInstance("-0123456789$separator")

When line with DigitsKeyListener is commented, key for separator is visible but only available separator is dot Keyboard with separator key

Do you have any ideas how to use comma as separator on stock keyboard?

Upvotes: 2

Views: 2353

Answers (3)

Kritika Monga
Kritika Monga

Reputation: 11

public class MainActivity extends Activity {

private EditText editText;
private String blockCharacterSet = "~#^|$%&*!";

private InputFilter filter = new InputFilter() {

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

        if (source != null && blockCharacterSet.contains(("" + source))) {
            return "";
        }
        return null;
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    editText = (EditText) findViewById(R.id.editText);
    editText.setFilters(new InputFilter[] { filter });
}

}

Upvotes: 0

ElegyD
ElegyD

Reputation: 4775

I had the same problem once. The stock keyboards on Samsung devices are horrible... There is just no way to display a numeric keyboard with a comma.

The best solution I found was just replacing the dot with a comma via a TextWatcher.
But only if the decimal separator of the default locale is a comma.

Allow both dot(.) and comma(,) in digits and set inputType to numberDecimal in XML:

<EditText
        android:id="@+id/editText_price"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:digits="1234567890,."
        android:imeOptions="actionDone"
        android:inputType="numberDecimal" />

And then add the TextWatcher to this editText:

val separator = DecimalFormatSymbols.getInstance().decimalSeparator
if (separator == ',') {
    editText_price.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit

        override fun afterTextChanged(s: Editable?) {
            if (s.toString().contains(".")) {
                val replaced = s.toString().replace('.', separator)
                editText_price.setText(replaced)
                editText_price.setSelection(replaced.length)
            }
        }
    })
}

Then to get the actual number of the String use this:

try {
    val price = DecimalFormat.getInstance().parse(editTextPrice.text.toString());
} catch (e: ParseException) {
    e.printStackTrace()
    editText_price.setError(getString(R.string.error))
}

Upvotes: 2

Stevie Kideckel
Stevie Kideckel

Reputation: 2106

The problem is that DigitsKeyListener does not specify the decimal/signed flag when using getInstance with a string of accepted characters. Since KeyListener overrides the input type of the EditText, after setting the KeyListener, your EditText now has inputType number and not numberDecimal or numberSigned.

Since DigitsKeyListener is quite useful, a simple fix is to simply delegate to it but use the correct input type. In Kotlin, this is amazingly easy:

class DecimalSignedDigitsKeyListener(digitsKeyListener: DigitsKeyListener) : 
    KeyListener by digitsKeyListener {

  override fun getInputType() =
    InputType.TYPE_CLASS_NUMBER or 
    InputType.TYPE_NUMBER_FLAG_DECIMAL or 
    InputType.TYPE_NUMBER_FLAG_SIGNED
}


val separator = DecimalFormatSymbols.getInstance().decimalSeparator
val digitsKeyListener = DigitsKeyListener.getInstance("<your digits>")
editTextValue.keyListener = DecimalSignedDigitsKeyListener(digitsKeyListener)

I'd recommend always accepting '.' in addition to any locale-specific separator, since not all keyboards will actually show the comma or other symbols.

Upvotes: 4

Related Questions