82

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);
}
Dinith Rukshan Kumara
  • 638
  • 2
  • 10
  • 19
Tim
  • 1,115
  • 1
  • 9
  • 12

15 Answers15

170

Based on @MarcinOrlowski answer, also you can use:

@Override
public void onBackPressed() {
    if (!searchView.isIconified()) {
        searchView.setIconified(true);
    } else {
        super.onBackPressed();
    }
}
Mohsen Afshin
  • 13,273
  • 10
  • 65
  • 90
  • 10
    Important, the above solution won't work if the you have set app:showAsAction="always" – UserK Jun 12 '17 at 15:47
  • 14
    Make sure to set searchView.setQuery("", false); in order to make searchView.setIconified(true); to work – Pushan Jan 03 '18 at 10:08
  • using searchView.setQuery("", false); before searchView.setIconified(true); worked for me, also if you put 2 successive searchView.setIconified(true); worked for me. – Ahmed Nezhi Jun 04 '21 at 14:04
58

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()

betorcs
  • 2,771
  • 22
  • 28
51

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.

blueware
  • 5,205
  • 1
  • 40
  • 60
38

this is the only thing that does it for me:

  toolbar.collapseActionView();
raklos
  • 28,027
  • 60
  • 183
  • 301
  • 3
    I tried all solution in this thread. this solution is the best for me. it is the only solution that made search icon back to top-right screen – Dika Nov 07 '17 at 02:06
  • IDE gives me "Actionbar.collapseActionView can only be called from within the same library group" error – Simon Aug 27 '18 at 01:19
  • 2
    `supportActionBar?.collapseActionView()` worked for me – HendraWD May 12 '19 at 20:19
23

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.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
  • Thanks for the response! What I'm mainly interested in though is whether there is a way to programmatically invoke a SearchView's close event i.e. Imitate an SearchView box "X" button press in code. – Tim Jul 06 '13 at 19:28
  • 2
    Thanks for all the help Marcin. It turns out what I actually wanted to do was the "iconify" my search actionview (my searchview is always on the action bar and never collapses into the options menu). Thanks for taking the time to help me and thanks for the tip on overriding "onBackPressed." – Tim Jul 06 '13 at 22:26
  • For me onBackPressed is not called. what other solution do I have ? I tried to listen for the focus on the searchview but that isn't called also.. – Ionut Negru Jan 15 '14 at 21:12
  • You do not expect `onBackPressed()` outside of Activity (i.e. in Fragment), do you? – Marcin Orlowski Jan 15 '14 at 21:38
  • 1
    For me, onBackPressed not being called at all. It seems the search view is actually eating up the back press and handling it. For example, I see that onMenuItemActionViewCollapsed() is called, but onBackPressed is not called. How can I override this? I even tried setting a Key Listener on the search view and it still doesn't work. – Ashok SoThree Apr 25 '14 at 21:27
  • I think this won't work if search view is in actionbar. It is always visible. So we it won't go to the else part. setIconified() works for me – Viswanath Lekshmanan Jan 27 '15 at 18:53
  • @AshokSoThree I've the same issue you described! I've the `Done` button, I don't know how to handle this button if the user searched with empty text! I want to hide the search view if the user click on `Done` button with empty text...do you've any ideas? Please share if you've any. Thanks! – Mohammed AlBanna Mar 02 '16 at 10:43
  • It seems that for `android.support.v7.widget.SearchView` the methods are `onActionViewCollapsed()` and `onActionViewExpanded()`. – Aspiring Dev Aug 15 '16 at 22:41
  • Where does menu come from? – Simon Aug 27 '18 at 01:05
21

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();
DoruChidean
  • 7,941
  • 1
  • 29
  • 33
4

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.

vishalsehgal
  • 364
  • 5
  • 11
2

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.

Dinith Rukshan Kumara
  • 638
  • 2
  • 10
  • 19
Codedroid
  • 518
  • 7
  • 16
2

Use:

searchView.setIconified(true);
Alex
  • 317
  • 2
  • 16
1

In Kotlin;

Firstly clear the typed text (optional)

searchView.isIconified = true

Second, close the searchview

searchView.onActionViewCollapsed()

Exstra, open searchview programatically

searchView.onActionViewExpanded()
Ahmet B.
  • 1,290
  • 10
  • 20
0

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();
Sergei K
  • 967
  • 11
  • 12
0

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"/>
SachinS
  • 2,223
  • 1
  • 15
  • 25
0

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" />
Deni Erdyneev
  • 1,779
  • 18
  • 26
0

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();
        }
    }
});
Pramod
  • 1,123
  • 2
  • 12
  • 33
0

Most Worked Solution:

MenuItem menuItem = ....//
menuItem.collapseActionView();
Roman
  • 2,464
  • 2
  • 17
  • 21