Android : KeyListener of EditText not working

2019-07-03 22:38发布

问题:

I'm trying to filter the input char of an EditText to allow only valid float value. (e.g. :"12,45", only one comma, ...).

For this, I use the KeyListener (dont confuse with onKeyListener or textChangeListener. I want to prevent the user from entering invalid data).

On Android 2.3.6 and 3.2 the keyListener.filter() and keyListener.getAcceptedChars() are not called and I can introduce any char (not limited to .getAcceptedChars())

I found little documentations about keyListener. If you got a good example or doc, I'm very interested.

Any clue why this is not working ?

What did I do wrong ?

Activity Code sample:

    @Override

    protected void onCreate(Bundle savedInstanceState)

    {

        super.onCreate(...);

        setContentView(R.layout.editTextTest_lyt);

...

 mEditTextTest = (EditText) findViewById(R.id.editTextTest);

mEditTextTest.setKeyListener(new NumberCommaDecimalKeyListenerTest());

...}

Layout Code sample:

editTextTest_lyt.xml:
            <EditText
                android:id="@+id/editTextTest"
                android:layout_height="fill_parent"
                android:layout_width="fill_parent"
                android:layout_weight="1"
                android:inputType="numberSigned|numberDecimal"
                android:ems="5"
                android:maxLength="9"
                android:maxLines="1"
                android:gravity="right|center_vertical"
                android:imeOptions="actionNext"/>

KeyListener Code sample:

public class NumberCommaDecimalKeyListenerTest extends NumberKeyListener {

private static final char[] mAccepted = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', ',' };
    private static final boolean    mSign = true;
    private static final boolean    mDecimal = true;

    @Override

    protected char[] getAcceptedChars()
    {
      Log.e("LODA", "KeylistenerTest.getAcceptedChars()"); // DONT show up in logs 
        return mAccepted;
    }

    public NumberCommaDecimalKeyListenerTest()
    { super();
  Log.e("LODA", "CREATE KeylistenerTest"); // show up in logs 
    }

    @Override
    public int getInputType()
    {
    Log.e("LODA", "KeylistenerTest.getInputType()"); // show up in logs 
        int contentType = InputType.TYPE_CLASS_NUMBER;
        if (mSign)
        {
            contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
        }
        if (mDecimal)
        {
            contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
        }
        return contentType;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
    {
    Log.e("LODA", "enter KeylistenerTest.filter"); // DONT show up in logs 

        // My logic will go here...

        // if user pressed '.', is changed for ','
        source = source.toString().replace(".", ",");
        source = source.toString().replace("6", "9");

        CharSequence out = super.filter(source, start, end, dest, dstart, dend);

        return out;
    }

}

回答1:

Looking at the Android docs they state in relation to KeyListener that:

Note that for most cases this interface has been superceded by general soft input methods as defined by InputMethod; it should only be used for cases where an application has its own on-screen keypad and also wants to process hard keyboard events to match it

And for the method getInputType():

If you return TYPE_NULL then no soft keyboard will provided. In other words, you must be providing your own key pad for on-screen input and the key listener will be used to handle input from a hard keyboard.

If you return any other value, a soft input method will be created when the user puts focus in the editor, which will provide a keypad and also consume hard key events. This means that the key listener will generally not be used, instead the soft input method will take care of managing key input as per the content type returned here.

So because you return a content type the KeyListener is ignored. Looks like this isn't possible then or did you find a work around?

Perhaps you could create a custom TextWatcher instead and then set this on the EditText using EditText.addTextChangedListener(TextWatcher textWatcher).?