Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Intercept back button from soft keyboard

Tags:

android

I have the activity with several input fields. When activity started soft keyboard is shown. When back button pressed soft keyboard closes and to close activity I need to press back button one more time.

So the question: is it possible to intercept back button to close soft keyboard and finish activity in one press of back button without creating custom InputMethodService?

P.S. I know how to intercept back button in other cases: onKeyDown() or onBackPressed() but it doesn't work in this case: only second press of back button is intercepted.

like image 668
Sergey Glotov Avatar asked Oct 15 '10 06:10

Sergey Glotov


People also ask

How do you intercept the flutter back button when keyboard is shown?

you can use the keyboard_visibility package to achieve this.

Do all Android devices have a back button?

All Android devices provide a Back button for this type of navigation, so you should not add a Back button to your app's UI. Depending on the user's Android device, this button might be a physical button or a software button.


2 Answers

onKeyDown() and onBackPressed() doesn't work for this case. You have to use onKeyPreIme.

Initially, you have to create custom edit text that extends EditText. And then you have to implement onKeyPreIme method which controls KeyEvent.KEYCODE_BACK. After this, one back press enough for solve your problem. This solution works for me perfectly.

CustomEditText.java

public class CustomEditText extends EditText {      public CustomEditText(Context context, AttributeSet attrs) {         super(context, attrs);     }      @Override     public boolean onKeyPreIme(int keyCode, KeyEvent event) {         if (keyCode == KeyEvent.KEYCODE_BACK) {             // User has pressed Back key. So hide the keyboard             InputMethodManager mgr = (InputMethodManager)                      getContext().getSystemService(Context.INPUT_METHOD_SERVICE);             mgr.hideSoftInputFromWindow(this.getWindowToken(), 0);             // TODO: Hide your view as you do it in your activity         }         return false; } 

In your XML

<com.YOURAPP.CustomEditText      android:id="@+id/CEditText"      android:layout_height="wrap_content"      android:layout_width="match_parent"/>  

In your Activity

public class MainActivity extends Activity {    private CustomEditText editText;     @Override    public void onCreate(Bundle savedInstanceState) {       super.onCreate(savedInstanceState);       setContentView(R.layout.activity_main);       editText = (CustomEditText) findViewById(R.id.CEditText);    } } 
like image 195
Alican Temel Avatar answered Oct 03 '22 11:10

Alican Temel


Yes, it is completely possible to show and hide the keyboard and intercept the calls to the back button. It is a little extra effort as it has been mentioned there is no direct way to do this in the API. The key is to override boolean dispatchKeyEventPreIme(KeyEvent) within a layout. What we do is create our layout. I chose RelativeLayout since it was the base of my Activity.

<?xml version="1.0" encoding="utf-8"?> <com.michaelhradek.superapp.utilities.SearchLayout     xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res/com.michaelhradek.superapp"     android:orientation="vertical"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:background="@color/white"> 

Inside our Activity we set up our input fields and call the setActivity(...) function.

private void initInputField() {     mInputField = (EditText) findViewById(R.id.searchInput);              InputMethodManager imm =          (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);      imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,              InputMethodManager.HIDE_IMPLICIT_ONLY);      mInputField.setOnEditorActionListener(new OnEditorActionListener() {          @Override         public boolean onEditorAction(TextView v, int actionId,                 KeyEvent event) {             if (actionId == EditorInfo.IME_ACTION_SEARCH) {                 performSearch();                 return true;             }              return false;         }     });      // Let the layout know we are going to be overriding the back button     SearchLayout.setSearchActivity(this); } 

Obviously, the initInputField() function sets up the input field. It also enables the enter key to execute the functionality (in my case a search).

@Override public void onBackPressed() {     // It's expensive, if running turn it off.     DataHelper.cancelSearch();     hideKeyboard();     super.onBackPressed(); } 

So when the onBackPressed() is called within our layout we then can do whatever we want like hide the keyboard:

private void hideKeyboard() {     InputMethodManager imm = (InputMethodManager)          getSystemService(Context.INPUT_METHOD_SERVICE);     imm.hideSoftInputFromWindow(mInputField.getWindowToken(), 0); } 

Anyway, here is my override of the RelativeLayout.

package com.michaelhradek.superapp.utilities;  import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.widget.RelativeLayout;  /**  * The root element in the search bar layout. This is a custom view just to   * override the handling of the back button.  *   */ public class SearchLayout extends RelativeLayout {      private static final String TAG = "SearchLayout";      private static Activity mSearchActivity;;      public SearchLayout(Context context, AttributeSet attrs) {         super(context, attrs);     }      public SearchLayout(Context context) {         super(context);     }      public static void setSearchActivity(Activity searchActivity) {         mSearchActivity = searchActivity;     }      /**      * Overrides the handling of the back key to move back to the       * previous sources or dismiss the search dialog, instead of       * dismissing the input method.      */     @Override     public boolean dispatchKeyEventPreIme(KeyEvent event) {         Log.d(TAG, "dispatchKeyEventPreIme(" + event + ")");         if (mSearchActivity != null &&                      event.getKeyCode() == KeyEvent.KEYCODE_BACK) {             KeyEvent.DispatcherState state = getKeyDispatcherState();             if (state != null) {                 if (event.getAction() == KeyEvent.ACTION_DOWN                         && event.getRepeatCount() == 0) {                     state.startTracking(event, this);                     return true;                 } else if (event.getAction() == KeyEvent.ACTION_UP                         && !event.isCanceled() && state.isTracking(event)) {                     mSearchActivity.onBackPressed();                     return true;                 }             }         }          return super.dispatchKeyEventPreIme(event);     } } 

Unfortunately I can't take all the credit. If you check the Android source for the quick SearchDialog box you will see where the idea came from.

like image 35
mhradek Avatar answered Oct 03 '22 11:10

mhradek