Kerkhofsd
Kerkhofsd

Reputation: 299

Android SearchView requires two clicks to expand the view

Short: When I click on my SearchViewIcon, the SearchView doesn't collapse/expand.

Long:

I"m using a SearchView to filter a RecyclerView in a Fragment that is in my MainActivity.

When I click on the SearchViewIcon (SearchView is iconified by default). I open the tab with the correct Fragment with this code:

searchView.setOnSearchClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewPager.setCurrentItem(2, false);
            }
        });

The Tab with the correct Fragment is opened like expected. Also the text input is shown, but the SearchView stays iconified. (See picture below.)

Application

My SearchView in XML:

<item
    android:id="@+id/action_search"
    android:orderInCategory="1"
    android:icon="@android:drawable/ic_menu_search"
    android:title="@string/menu_item_search_title"
    app:showAsAction="ifRoom"
    app:queryHint="Search name or function"
    app:actionViewClass="android.support.v7.widget.SearchView" />

Things I already tried:

Setting my showAsAction to always or ifRoom|collapseActionView

app:showAsAction="always"
app:showAsAction="ifRoom|collapseActionView"

Request focus on my SearchView:

searchView.requestFocus();

Expanding my SearchViewItem:

MenuItem searchViewItem = menu.findItem(R.id.action_search);
searchViewItem.expandActionView();

But non of these things worked...

EDIT Like the title says, if I click the SearchViewIcon again, the SearchView does expand.

Upvotes: 9

Views: 2558

Answers (3)

Mab
Mab

Reputation: 412

Thanks to the upvoted answer above, this is what I did

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    menuInflater.inflate(R.menu.contacts_menu, menu)
    val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
    val searchItem = menu.findItem(R.id.action_search)
    val searchView = searchItem.actionView as SearchView

    searchView.queryHint = "Search contacts"
    searchView.setSearchableInfo(searchManager.getSearchableInfo(componentName))
    searchView.isIconifiedByDefault = false

    searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
        override fun onMenuItemActionExpand(item: MenuItem): Boolean {
            Handler(Looper.getMainLooper()).post {
                searchView.requestFocus()
                val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.showSoftInput(searchView.findFocus(), 0)
            }
            return true
        }

        override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
            // Can choose to hide keyboard here 
            adapter.submitList(originalList)
            binding.recyclerView.scrollToPosition(0)
            return true
        }
    })

    searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
        override fun onQueryTextSubmit(query: String?): Boolean {
            return true
        }

        override fun onQueryTextChange(newText: String?): Boolean {
            filterContacts(newText.orEmpty())
            return true
        }
    })

    return true
}

Upvotes: 0

HAXM
HAXM

Reputation: 3908

The simplest solution is to use always option for app:showAsAction:

app:showAsAction="always"

<item
android:id="@+id/action_search"
android:icon="@android:drawable/ic_menu_search"
android:title="search"
app:showAsAction="always"
app:actionViewClass="android.widget.SearchView"
/>

Upvotes: 1

Re&#39;em
Re&#39;em

Reputation: 1937

I've also encountered a similar problem, and was able to solve it. The main problems I've needed to solve were:

  1. searchView was not expanding by default
  2. the search EditText didn't get a focus until a second click
  3. even after solving (2), the keyboard didn't show up until a second click

solutions:

  1. in menu.xml need to define app:showAsAction as "collapseActionView" + in java code need also to call searchView.setIconifiedByDefault(false) for the expansion to take priority over the iconification (that is - when the icon is pressed, expand and don't stay in icon mode)
  2. add a MenuItem.OnActionExpandListener for your search menu-item object and use a handler to post a runnable that will request focus to your search-view object. (why runnable? because requesting focus when the menu is still not fully inflated is not guaranteed to work. When requesting focus in a handler-runnable, I'm making sure the focus request happens AFTER all the work in the onCreateOptionsMenu() is ready and finished.
  3. in The same defined runnable from (2), also ask android OS to show the keyboard.

complete code solving all those problems:

menu.xml:

    <item
    android:id="@+id/searchContacts"
    android:icon="@drawable/ic_search_white_24dp"
    android:title="search"
    app:showAsAction="collapseActionView|always"
    app:actionViewClass="android.widget.SearchView"
    />
 <!-- and of course your other menu items -->

searchable configuration:

Need to create such xml file. right-click your res folder and choose new --> android resource file. put whatever you want as file name ("searchable" will work ok, for example), and choose XML as resource type. Then copy & paste this code in the created file (replace the hint string with your own):

<?xml version="1.0" encoding="utf-8"?>

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="put here your hint string to be shown"
    />

MainActivity:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu, menu);
        implementSearch(menu);
        return true;
    }

    private void implementSearch(final Menu menu) {
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        final MenuItem searchMenuItem = menu.findItem(R.id.searchContacts);
        final SearchView searchView = (SearchView) searchMenuItem.getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setIconifiedByDefault(false);

        searchMenuItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener(){
            @Override
            public boolean onMenuItemActionExpand(MenuItem item){
                // the search view is now open. add your logic if you want
                new Handler().post(new Runnable() {
                    @Override
                    public void run() {
                        searchView.requestFocus();
                        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                        if (imm != null) { // it's never null. I've added this line just to make the compiler happy
                            imm.showSoftInput(searchView.findFocus(), 0);
                        }


                    }
                });
                return true;
            }


            @Override
            public boolean onMenuItemActionCollapse(MenuItem item){
                // the search view is closing. add your logic if you want
                return true;
            }

        });

    }

Also, if you want to use your own callbacks for the search's text change and submitted (instead of Android intents), in the implementSearch() method add a call to searchMenuItem.setOnActionExpandListener(new SearchView.OnQueryTextListener({...})).

view this SO question for more details

Upvotes: 6

Related Questions