23

When using AutoCompleteTextView, the dropdown suggestion list appears with the software keyboard still visible. This makes sense, as it is often a lot more efficient to type ensuing characters to narrow the list.

But if the user wants to navigate the suggestion list, it becomes extremely tedious with the software keyboard still up (this is even more of a problem when the device is in landscape orientation). Navigating the list is a lot easier without the keyboard hogging the screen space. Unfortunately, the default behaviour removes the list first when you press the back key (even though in the software versions of the back key it is showing the image that says 'pressing this will hide the keyboard').

Here's a barebones example that demonstrates what I'm talking about:

public class Main2 extends Activity {
    private static final String[] items = {
            "One",
            "Two",
            "Three",
            "Four",
            "Five"
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        AutoCompleteTextView actv = new AutoCompleteTextView(this);
        actv.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        actv.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));
        actv.setThreshold(1);

        LinearLayout ll = new LinearLayout(this);
        ll.setOrientation(LinearLayout.VERTICAL);
        ll.addView(actv);

        setContentView(ll);
    }
}

Besides the fact that this is unintuitive (the back key hint is suggesting that the back press will be sent to the keyboard), it makes navigating AutoCompleteTextView suggestions extremely tiresome.

What is the least intrusive way (e.g. catching the back in on onBackPressed() in every activity and routing it accordingly would definitely not be ideal) to make the first back press hide the keyboard, and the second remove the suggestion list?

btalb
  • 6,937
  • 11
  • 36
  • 44

2 Answers2

37

You can achieve that by override-ing onKeyPreIme in your custom AutoCompleteTextView.

public class CustomAutoCompleteTextView extends AutoCompleteTextView {

    public CustomAutoCompleteTextView(Context context) {
        super(context);
    }

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

    public CustomAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing()) {
            InputMethodManager inputManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            
            if (inputManager.hideSoftInputFromWindow(findFocus().getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS)) {    
                return true;
            }
        }

        return super.onKeyPreIme(keyCode, event);
    }

}
Mostafa Gazar
  • 2,487
  • 18
  • 23
  • Good solution but it doesn't seem to work. The key is correctly grabbed and recognised (i.e. hideSoftInputFromWindow is triggered) but the keyboard doesn't actually disappear. Could it be clashing with something in the `EditText` that keeps the soft keyboard up while the view has focus? – btalb Nov 23 '14 at 12:08
  • Can you try getApplicationWindowToken() instead – Mostafa Gazar Nov 23 '14 at 12:21
  • Same result still unfortunately – btalb Nov 23 '14 at 14:39
  • I tested it on 4.4 and it is working fine, what is your setup? and testing device – Mostafa Gazar Nov 23 '14 at 14:49
  • 1
    Just tried it back in the blank project with only the code from the question and it works. There must be something clashing with this in my more complex instance. Nonetheless, thanks for the nice simple solution! – btalb Nov 23 '14 at 15:18
  • This has a drastic side effect - the next back press will now no longer remove the popup (isAcceptingText() is **always** true). As this question (http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android?lq=1) shows, adapting this to detect if keyboard is closed is not easy at all. – btalb Nov 24 '14 at 02:04
  • A workaround would be to use focus state as keyboard visibility indicator (review updated code) but you are right it can be unreliable you might have to track root view activity hight to tell if it is visible or not. – Mostafa Gazar Nov 24 '14 at 07:48
  • I've decided to add performClick() handle to mIsKeyboardVisible to true – Alexey Dec 03 '14 at 13:59
  • not work this solution seems that never called this method –  Nov 23 '15 at 09:26
  • Unfortunately, it doesn't work reliably - sometimes the keyboard gets closed, sometimes the suggestion dropdown gets closed instead. As long as no text has been entered, it's usually the keyboard that gets closed, but as soon as some characters have been entered, only the suggestion dropdown gets closed anymore... – SePröbläm Dec 06 '15 at 16:38
  • I've edited the code and it seems to work, at least on the few devices I've tried. With the current code, on a second back tap the popup is dismissed. – Maragues Feb 01 '16 at 13:23
  • 1
    You made my day. Thanks alot! – Kuls Mar 21 '17 at 12:40
  • 1
    Awsomeeeeeeee!! – OhhhThatVarun Sep 14 '19 at 20:04
  • 1
    MashaAllah, excellent, work in Android 10 – Noor Hossain Feb 10 '21 at 19:13
3

set DismissClickListener like this

 autoCompleteTextView.setOnDismissListener(new AutoCompleteTextView.OnDismissListener() {
            @Override
            public void onDismiss() {
                InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                in.hideSoftInputFromWindow(getCurrentFocus().getApplicationWindowToken(), 0);
            }
        });
Anirudh Sharma
  • 7,968
  • 13
  • 40
  • 42
Krishna Meena
  • 5,693
  • 5
  • 32
  • 44