29

How can I handle the event of pressing back key while typing on an EditText? When the virtual keyboard is shown and the user presses back, it gets hidden. I want to handle this event, but setting an OnKeyListener in the EditText does not help.

Flávio Faria
  • 6,575
  • 3
  • 39
  • 59

5 Answers5

77

Thank you Reno. It probably seems to work, but I managed to solve it differently.

I overrode EditText's onKeyPreIme(int keyCode, KeyEvent event). This method intercepts keypresses on the IME. =D

public boolean onKeyPreIme(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && 
        event.getAction() == KeyEvent.ACTION_UP) {
            // do your stuff
            return false;
    }
    return super.dispatchKeyEvent(event);
}
Flávio Faria
  • 6,575
  • 3
  • 39
  • 59
  • if you want to handle in any other layout other than Edittext see this link http://stackoverflow.com/a/5811630/341443. its working fine – praveenb May 09 '12 at 12:58
  • 1
    sorry, how to override EditText's onKeyPreIme(int keyCode, KeyEvent event). – UmAnusorn Aug 13 '15 at 08:41
  • 1
    @umitems you'll need to extend the EditText class and override the `onKeyPreIme` method from there. Then, in your xml, instead of using an `EditText`, you'll need to use com.your.package.CustomEditText instead. See here: http://stackoverflow.com/a/28719420/1421014 – h_k Nov 12 '15 at 17:14
  • Thank you ,btw Why I cannot see your name? – UmAnusorn Nov 13 '15 at 04:00
15

This does not work ?

edText.setOnKeyListener(new OnKeyListener()
    {
        public boolean onKey(View v, int keyCode, KeyEvent event)
        {
            if (event.getAction() == KeyEvent.ACTION_DOWN)
            {
                //check if the right key was pressed
                if (keyCode == KeyEvent.KEYCODE_BACK)
                {

                    return true;
                }
            }
            return false;
        }
    });

EDIT :

Alright this is depressing. Android does not send IME events on closure of the qwerty keypad. This is the only workaround that ive come across. I hope it works for you as well.

Community
  • 1
  • 1
Reno
  • 33,594
  • 11
  • 89
  • 102
  • Oh you want to *stop* the keypad from going down ? How do you plan on letting the user do it then ? – Reno Feb 25 '11 at 04:24
  • No, I don't want to stop the keypad from going down. When the keypad goes down, I will start an animation on a view. – Flávio Faria Feb 25 '11 at 04:28
  • It doesn't work.You should use onKeyPreIme.The method you mentioned works with enter and other keys... Why did you get 15 upvotes? lol – Steve Moretz Jan 26 '19 at 18:47
10

I have no idea why this is the case but OnKeyListener works if you just purely override onKeyPreIme on your custom EditText.

customEditText.setOnKeyListener((v, keyCode, event) -> {
            if(event.getAction() == KeyEvent.ACTION_DOWN) {
                switch (keyCode) {
                    case KeyEvent.KEYCODE_BACK:
                        getPresenter().onBackPressed();
                        break;
                }
            }
            return false;
        }); 

@Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        return super.dispatchKeyEvent(event);
    }
Rubin Yoo
  • 2,674
  • 2
  • 24
  • 32
0

Non of the other answers were working for me in SearchView, I've finally end up with overriding dispatchKeyEventPreIme(...) method in my custom view:

class ImeAwareSearchView @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : SearchView(context, attrs, defStyleAttr) {

    var onKeyEventPreImeListener: OnKeyEventPreImeListener? = null

    override fun dispatchKeyEventPreIme(event: KeyEvent?): Boolean {
        onKeyEventPreImeListener?.onPreImeKeyEvent()
        return false
    }
}

The listener looks like this:

interface OnKeyEventPreImeListener {

    fun onPreImeKeyEvent()
}

And I'm setting it in Fragment to hide my search row:

search_input.onKeyEventPreImeListener = object: OnKeyEventPreImeListener {
    override fun onPreImeKeyEvent() {
        hideSearchRow()
    }
}

Note that dispatchKeyEventPreIme(...) method is called twice, so make sure you don't do your staff on event twice as well.

Micer
  • 8,731
  • 3
  • 79
  • 73
0

Finally, I am able to do this by these 3 steps:

1. Creating Custom EditText Class to handle Back Press:

public class CustomEditTextWithBackPressEvent extends androidx.appcompat.widget.AppCompatEditText {

    private MyEditTextListener onBackPressListener;

    public CustomEditTextWithBackPressEvent(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setOnBackPressListener(MyEditTextListener onBackPressListener) {
        this.onBackPressListener = onBackPressListener;
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK &&
            event.getAction() == KeyEvent.ACTION_UP) {
            //back button pressed
            if (Objects.requireNonNull(ViewCompat.getRootWindowInsets(getRootView())).isVisible(WindowInsetsCompat.Type.ime())) {
            //keyboard is open
                onBackPressListener.callback();
            }
            return false;
        }
        return super.dispatchKeyEvent(event);
    }

    public interface MyEditTextListener {
        void callback();
    }
}

2. Replace your normal EditText with this CustomEditTextWithBackPressEvent in XML

<CustomEditTextWithBackPressEvent
    android:id="@+id/etSearch"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="@string/search_hint"
    android:imeOptions="actionSearch"
    android:inputType="text"
    android:maxLines="1" />

3. Handle Back Press:

binding.etSearch.setOnBackPressListener(() -> {
    //handle back press when keyboard is open
});
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Kishan Solanki
  • 13,761
  • 4
  • 85
  • 82