How do I close a SearchView programmatically?

I currently have a SearchView in the action bar of my app. When I click the search icon, the SearchView expands and the keyboard pops up as expected. Clicking the "X" in the SearchView box closes the SearchView as expected. However, when the SearchView is activated and I press the "back" button, my app is exited. This is the correct behavior, but what I am trying to do now is to capture back button press and just have it close the SearchView (not my app) when the SearchView is visible. Is there a way to invoke the SearchView OnCloseListener() programmatically on a back button press? For example, something like this:

// On a back button press, if we are currently searching,
// close the SearchView. Otherwise, invoke normal back button
// behavior.
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (isSearchViewVisible) {
SearchView searchView = (SearchView) menu.findItem(R.id.searchBox)
.getActionView();


// This method does not exist
searchView.invokeClose();
return true;
}
}
return super.onKeyDown(keyCode, event);
}
71787 次浏览

To intercept BACK button override onBackPressed() (see docs)

@Override
public void onBackPressed() {


if (isSearchViewVisible) {
SearchView searchView = (SearchView) menu.findItem(R.id.searchBox)
.getActionView();


// This method does not exist
searchView.invokeClose();
} else {
super.onBackPressed();
}
}

EDIT:

Docs say:

If necessary, you can expand or collapse the action view in your own code by calling expandActionView() and collapseActionView() on the MenuItem.

Based on @MarcinOrlowski answer, also you can use:

@Override
public void onBackPressed() {
if (!searchView.isIconified()) {
searchView.setIconified(true);
} else {
super.onBackPressed();
}
}

I prefer !searchView.isIconified() over if(isSearchViewVisible) inside the onBackPressed() method as option 2 does not work when you have fragments added in your fragmentmanager's backstack that you would like to show when the back button is pressed.

Use

searchView.setIconified(true)

I also used MenuItemCompat.collapseActionView

MenuItemCompat.collapseActionView(menuItem)

EDITED

This method was deprecated in API level 26.1.0. Use collapseActionView() directly.

MenuItem#collapseActionView()

There is a simple way to do this:

@Override
public void onBackPressed() {
if (!searchView.isIconified()) {
searchView.onActionViewCollapsed();
} else {
super.onBackPressed();
}
}

or use:

myToolBar.collapseActionView();

This will make the searchView to collapse before you press the back then the back action will be called.

Both solutions will work.

Use:

searchView.setIconified(true);

My way:

  1. Create CustomSearchView class


public class CustomSearchView extends SearchView{
public CustomSearchView(final Context context) {
super(context);
this.setIconifiedByDefault(true);
}


@Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
event.getAction() == KeyEvent.ACTION_UP) {
this.onActionViewCollapsed();
}
return super.dispatchKeyEventPreIme(event);
}
}


  1. Add actionViewClass
<item
android:id="@+id/menu_search"
android:title="@string/menu_search"
android:icon="@drawable/ic_search"
android:showAsAction="collapseActionView|ifRoom"
android:actionViewClass="com.myapp.CustomSearchView"/>
  1. Create CustomSearchView into onCreateOptionsMenu
CustomSearchView searchView = (CustomSearchView)menu.findItem(R.id.menu_search).getActionView();

If you are not use any function in onBackPressed() method ,remove it from your Activity.So that the SearchView itself handle the onBackPress event.

I am using SearchView as

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchview = (SearchView) MenuItemCompat.getActionView(searchItem);
searchview.setIconifiedByDefault(true);
searchview.setOnQueryTextListener(this);
searchview.setSubmitButtonEnabled(true);
searchview.setQueryHint("Search Here");
super.onCreateOptionsMenu(menu, inflater);
}

and my menu.xml as follows

<item
android:id="@+id/action_search"
android:icon="@drawable/search_tool"
android:orderInCategory="1"
android:title="Search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always|collapseActionView"/>

this is the only thing that does it for me:

  toolbar.collapseActionView();

Also you can use collapseActionView. It automatically handle back button, collapsing SearchView

<item
android:id="@+id/action_search"
android:icon="@drawable/ic_magnify"
android:title="@string/action_title_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />

if you have input on your searchView

mSearchView.setIconified(true);

will only clear the text.

The correct method to close a searchView is

mSearchView.onActionViewCollapsed();

No need to use onBackPressed() method for this!! I found the solution, do only as I mentioned below so that the SearchView itself handle the on back button press event.

Inside your onCreateOptionsMenu() method,

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem menuItem = menu.findItem(R.id.action_search);
SearchView searchview = (SearchView) menuItem.getActionView();
searchview.setIconifiedByDefault(true);
searchview.setQueryHint("Enter your keyword");
searchview.setOnQueryTextListener(this);
super.onCreateOptionsMenu(menu, inflater);
}

In your menu.xml add showAsAction attribute and set its values as "always|collapseActionView"

<item
android:id="@+id/action_search_item"
android:title="Search"
android:icon="@drawable/ic_search_logo"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"/>

And you're ready to go ;)

P.S. - I was searching for a solution from a long time and now I found one, hope it helps you all.

The following worked for me. I am trying to close search-view from Fragment in Jetpack NavigationView when a user clicks the back button -

requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() {

        try {
DashboardActivity activity = (DashboardActivity) getActivity();
if (activity!=null) {
if (!activity.mSearchView.isIconified()) {
activity.mSearchView.setQuery("",false);
activity.mSearchView.setIconified(true);
} else {
NavController navController = Navigation.findNavController(activity, R.id.nav_host_fragment);
navController.popBackStack();
}
}


}catch (Exception e){
e.printStackTrace();
}
}
});

In Kotlin;

Firstly clear the typed text (optional)

searchView.isIconified = true

Second, close the searchview

searchView.onActionViewCollapsed()

Exstra, open searchview programatically

searchView.onActionViewExpanded()

Most Worked Solution:

MenuItem menuItem = ....//
menuItem.collapseActionView();