0

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()));
Ersen Osman
  • 7,067
  • 8
  • 47
  • 80
  • i dont understand the reason for not using a std SearchView – pskink Aug 25 '15 at 18:14
  • @pskink Hi I added some more reasons why I do not use search view at the bottom of my answer. – Ersen Osman Aug 26 '15 at 06:29
  • 1) you dont need a `ContentProvider` + `searchable`s for that: you could use `setSuggestionsAdapter(CursorAdapter adapter)` 2) you can always use `MatrixCursor` when you need `Cursor` interface: `mc.newRow().add(...).add(...)....` – pskink Aug 26 '15 at 06:36
  • @pskink interesting, so you are saying that I have to convert my array list to a MaxtrixCursor in order to use it for the CursorAdapter to get suggestions? Do you have an example of how It looks? i.e. does the suggestions appear like a auto complete text view? – Ersen Osman Aug 26 '15 at 06:46
  • call `setSuggestionsAdapter` with an adapter taken for example from this answer: http://stackoverflow.com/a/19860624/2252830 – pskink Aug 26 '15 at 06:51
  • Thanks for pointing me to this. I found this link too http://ramannanda.blogspot.co.uk/2014/10/android-searchview-integration-with.html – Ersen Osman Aug 26 '15 at 06:56
  • @pskink So does the CursorAdapter implement filterable? How does the auto complete query the data – Ersen Osman Aug 26 '15 at 07:00
  • 1
    yes `CursorAdapter` implements `Filterable`, you can filter things out via `FilterQueryProvider` or directly by overiding `runQueryOnBackgroundThread(CharSequence constraint)` try to add the above code snippet to `onCreate` and add some `Log.d` calls in `runQuery` – pskink Aug 26 '15 at 07:14
  • @pskink thanks i implemented it – Ersen Osman Aug 26 '15 at 11:14
  • @pskink However the search view does not do point number 2. Do you know how to do it? – Ersen Osman Aug 26 '15 at 11:15
  • @pskink hi do you know how to set the search threshold with this method? I use a searchable config but it does not work always defaults to 2 characters – Ersen Osman Sep 03 '15 at 11:37
  • how do you use your SearchView? where is your code? – pskink Sep 03 '15 at 11:45
  • @pskink Sorry for the delay, i added all the code – Ersen Osman Sep 03 '15 at 14:26
  • Log.d what `searchManager.getSearchableInfo()` returns – pskink Sep 03 '15 at 14:43
  • @pskink When i called toString after getSeachableInfo, turns out its null and i get a null pointer. So that whole line searchManager.getSearchableInfo(getActivity().getComponentName()) gives me null – Ersen Osman Sep 03 '15 at 15:04
  • searchable.xml has to have `android:label`, not `android:hint`, for example: android:label="@string/search_label" android:searchSuggestThreshold="1" – pskink Sep 03 '15 at 15:06
  • @pskink Just tried it, same problems – Ersen Osman Sep 03 '15 at 15:14
  • do you have action SEARCH in your tag? – pskink Sep 03 '15 at 15:15
  • @pskink No. I did not use that because i do not have a separate search activity but i am using fragments to 1 activity – Ersen Osman Sep 03 '15 at 15:17
  • reading from sources the only way to set the threshold is via searchable.xml so you have to deal with it – pskink Sep 03 '15 at 15:18
  • @pskink same problem :( – Ersen Osman Sep 03 '15 at 15:22
  • so search the inet, why it is null... – pskink Sep 03 '15 at 15:25
  • @pskink Been searching for a while nothing so far. I might just go back to AutoCompleteTextView because i had it working on 1 threshold on that – Ersen Osman Sep 03 '15 at 15:26
  • so use ACTV, set the same Adapter for filtering purposes – pskink Sep 03 '15 at 15:46
  • @pskink yeah but i will have the original problem to solve (see title) :P – Ersen Osman Sep 03 '15 at 15:59
  • ok so find why getSearchableInfo() is null, i just tried it and my getSearchableInfo() != null – pskink Sep 03 '15 at 16:47
  • Would it be ok for you the post the code? So i can compare? I've been looking cant see whats wrong. – Ersen Osman Sep 03 '15 at 16:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/88724/discussion-between-john-carter-and-pskink). – Ersen Osman Sep 03 '15 at 16:57
  • @pskink Would it be ok for you the post the code? So i can compare? I've been looking cant see whats wrong – Ersen Osman Sep 03 '15 at 17:06
  • http://codeshare.io/MgANv – pskink Sep 03 '15 at 17:10
  • @pskink Thanks. Will try and compare soon. Out of curiosity, is it working? The 1 character threshold for search ? – Ersen Osman Sep 04 '15 at 08:43

1 Answers1

1

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;
    }
Ersen Osman
  • 7,067
  • 8
  • 47
  • 80
  • personally i prefer: `cursor.newRow().add(id++).add(foof.getName()).add(food.getReferenceNumber())` – pskink Aug 26 '15 at 11:44