Ersen Osman
Ersen Osman

Reputation: 7247

Android: AutoCompleteTextView as Collapsable Action View focus issues

Hi so for my needs i cannot use SearchView because i am filtering an array list that contains some custom object plus this AutoCompleteTextView is embedded into the toolbar as a menu item

<item
    android:id="@+id/searchFoodMenuItem"
    android:title="@string/generic.search"
    app:actionLayout="@layout/view_search_food_auto_complete"
    android:orderInCategory="1"
    android:icon="@drawable/ic_search_white_48dp"
    app:showAsAction="ifRoom|collapseActionView"
    />

I wish to mimic the behaviour of searchview in these cases:

  1. Clicking on the icon puts the auto complete text view in focus and brings up the key board (I have kind of achieved this but i have a small issue that i need help with)

  2. While the auto complete text view is in focus, clicking anywhere else on the screen that is not the keyboard will remove the focus of the auto complete text view rather than passing the touch to the view that was pressed.

Some code

So i wrote my own extension of the AutoCompleteTextView.

Here is some key snippets

The part below simply closes / opens the keyboard when the focus of the view has changed. This also includes clicking on it and pressing back on the soft keyboard.

@Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);

        InputMethodManager inputMethodManager = (InputMethodManager) getContext()
                .getSystemService(Context.INPUT_METHOD_SERVICE);

        if (focused) {
            inputMethodManager.showSoftInput(this, 0);
        } else {
            setFocusableInTouchMode(false);
            inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
        }
    }

 @Override
    public boolean performClick() {
        setFocusableInTouchMode(true);
        requestFocus();
        return super.performClick();
    }

 @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
            clearFocus();
        }

        return false;
    }

Below is the code which puts the view into focus when the menu item is expanded

MenuItemCompat.setOnActionExpandListener(mSearchFoodMenuItem, new MenuItemCompat.OnActionExpandListener() {
           @Override
           public boolean onMenuItemActionExpand(MenuItem item) {
                mSearchFoodInputField.post(new Runnable() {
                    @Override
                    public void run() {
                        DebugUtils.Log("onMenuItemActionExpand");
                        mSearchFoodInputField.requestFocus();
                    }
                });
               return true;
           }

           @Override
           public boolean onMenuItemActionCollapse(MenuItem item) {
               return true;
           }
       });

The above works the first time, i.e. if i click on the menu item, the auto complete text view becomes focused and the key board appears. All is well, but if i collapse this menu item and do it again, it no longer becomes focused and i am not sure why.

More reasons I am not using SearchView

The main reason I do not want to use it is because I want to display search suggestions based on my array list of objects. My understanding of the API tells me that search view can only do this on a database Cursor (which I am not using)

Search view code

The menu

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/action_search"
        android:title="@string/generic.search"
        android:icon="@drawable/ic_search_white_48dp"
        app:showAsAction="ifRoom|collapseActionView"
        android:iconifiedByDefault="true"
        app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>

In onCreateOptionsMenu

  @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.piece_discover_menu, menu);
        mSearchMenuItem = menu.findItem(R.id.action_search);
        mSearchView = (SearchView) MenuItemCompat.getActionView(mSearchMenuItem);
        mSearchView.setOnQueryTextListener(this);
        mSearchView.setOnSuggestionListener(this);
        mSearchView.setSuggestionsAdapter(mFoodSearchAdapter); 
    }

Below is what i tried

I made a searchable config

Note i tried with and without completetionThreshold

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:hint=“@string/search_hint”
   android:searchSuggestThreshold=“1”
 android:completionThreshold=“1”
</searchable>

Me applying the search config

Note this was declared between the application tags

 <meta-data android:name="android.app.searchable"
            android:resource="@xml/searchable" />

Me adding the search manager

     SearchManager searchManager =
               (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
 mSearchView.setSearchableInfo(
          searchManager.getSearchableInfo(getActivity().getComponentName()));

Upvotes: 0

Views: 524

Answers (1)

Ersen Osman
Ersen Osman

Reputation: 7247

Thanks to pskink , I used a search view instead. To get suggestions like the AutoCompleteTextView i used a cursorAdapter. However if like me you had an array list of some Java object, you need to convert it to a Cursor as follows.

 public static final String[] COLUMNS = new String[]{"_id","foodName","foodReference"};

 public static final int ID_INDEX = 0, FOOD_NAME_INDEX = 1, FOOD_REFERENCE_INDEX = 2;

  private MatrixCursor convertToCursor (ArrayList<Food> foods){
        MatrixCursor cursor =  new MatrixCursor(COLUMNS);
        for(Food food : foods){
            String[]row = new String[COLUMNS.length];
            row[ID_INDEX] = Integer.toString(mFoods.indexOf(food));
            row[FOOD_NAME_INDEX] = food.getName();
            row[FOOD_REFERENCE_INDEX] = food.getReferenceNumber();
            cursor.addRow(row);
        }
        return cursor;
    }

Upvotes: 1

Related Questions