How to retain soft keyboard state after invalidateOptionsMenu android - android

Hi I have used searchview like below,
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.all_menu, menu);
SearchManager manager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setSearchableInfo(manager.getSearchableInfo(getActivity().getComponentName()));
searchTextView = (AutoCompleteTextView) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
try {
Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes");
mCursorDrawableRes.setAccessible(true);
mCursorDrawableRes.set(searchTextView, R.drawable.cursor); //This sets the cursor resource ID to 0 or #null which will make it visible on white background
} catch (Exception e) {
e.printStackTrace();
}
if (searchView != null) {
searchView.setQueryHint(getString(R.string.search));
searchView.setOnQueryTextListener(this);
}
mMenu = menu;
setNotificationCount(mMenu);
}
and i'm invalidating notification count using the below code,
getSupportActionBar().invalidateOptionsMenu();
but invalidating the menu will close the opened keyboard. I want to retain the keyboard state even after invalidate the action bar menus. So I have tried to retain keyboard state using below code,
KeyboardVisibilityEvent.setEventListener(getActivity(), new KeyboardVisibilityEventListener() {
#Override
public void onVisibilityChanged(boolean isOpen) {
if(!isFristTime){
Log.d("ss","keyboard status before validated "+isKeyboardOpened);
isKeyboardOpened = isOpen;
isFristTime = true;
}
}
});
getSupportActionBar().invalidateOptionsMenu();
Log.d("ss","keyboard status after validated "+isKeyboardOpened);
if(isKeyboardOpened){
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
try {
Log.d("ss","keyboard status in try ");
Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes");
mCursorDrawableRes.setAccessible(true);
mCursorDrawableRes.set(searchTextView, R.drawable.cursor); //This sets the cursor resource ID to 0 or #null which will make it visible on white background
BDevice.showSoftKeyboard(getActivity(), searchTextView);
isKeyboardOpened = false;
getSupportActionBar().invalidateOptionsMenu();
} catch (Exception e) {
Log.d("ss","keyboard status in catch ");
e.printStackTrace();
}
}
}, 1000);
}
But this will not work. Now I want to open the soft keyboard if its opened before invalidating the menu. Could you please suggest me an idea to retain the keyboard state after invalidate the menu?

I have found the solution. Whenever validating the action bar menu onCreateOptionsMenu gets call. So I have store the keyboard state very first time the keyboard gets opened and checking the keyboard state in onCreateOptionsMenu after validating it. Then i use to expand the searchview and open the soft keyboard programmatically like below,
Global variables
private boolean isFristTime = false, isKeyboardOpened = false;
private String mCurrentQuery = "";
Then my code in onCreateOptionsMenu method
if(isKeyboardOpened) {
searchView.setIconified(false);
searchItem.expandActionView();
searchView.requestFocus();
if(!TextUtils.isEmpty(mCurrentQuery)){
searchView.setQuery(mCurrentQuery, false);
}else{
searchView.setQueryHint(getString(R.string.search));
}
searchView.setIconifiedByDefault(true);
BDevice.showSoftKeyboard(getActivity(), searchTextView);
isKeyboardOpened = false;
}
and i'm getting my keyboard start before validation like below,
KeyboardVisibilityEvent.setEventListener(getActivity(), new KeyboardVisibilityEventListener() {
#Override
public void onVisibilityChanged(boolean isOpen) {
if(!isFristTime){
isKeyboardOpened = isOpen;
isFristTime = true;
}
}
});
getSupportActionBar().invalidateOptionsMenu();
and getting my query inside the onQueryTextChange method
#Override
public boolean onQueryTextChange(String newText) {
mCurrentQuery = newText;
return true;
}
Happy Coding...

Related

Dimming and undimming window below a popup - strange behaviour

In a project the behaviour I intend is:
Content below a popup window should be dimmed
When the close button on the popup is pressed, the content below should be undimmed.
Point (1) is achieved but point (2) is not - the problem being that a recyclerview component (the only component contained) is not undimmed.
As you can see, the RecylerView is still greyed out after popup is dimissed
The approach I've used is this:
Dimming the window below
Obtain a reference to the constraintlayout
set it's alpha value (opacity) 100
Undimming the window below
the popup has a close button
on press, the alpha value of the constraintlayout is re-set to zero (transparent)
Here's some of the code I'm using:
in the MainActivity's onCreate() method:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = (ConstraintLayout) findViewById(R.id.activity_main_constraint_layout);
constraintLayout.getForeground().setAlpha(0); // alpha 225 = completely transparent; alpha 0 = completely opaque
context = getApplicationContext();
MyAdapter adapter = new MyAdapter();
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
inflatePopupView();
acquirePopupChildren();
handleIntent(getIntent());
}
A searchview is implemented in the app bar:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.appbar_menu, menu);
// associate searchable configuration with the SearchView
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.search_box).getActionView();
// the SearcheableInfo object will be obtained from this activity's <meta-data> in manifest
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(true);
// to close the searchview the 'x' button must be pressed twice:
// - once to clear the typed query and once again to iconify (collapse) searchview.
// Because I've set a listener on the searchView - I don't need a separate searchable activity
// or searchable.xml config file. The searchView listeners themselves will handle the search.
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
searchView.setIconified(true); // clear the query text
searchView.setIconified(true); // collapse the searchview
doSearch(query);
return true; // true because the searchview itself handles search
}
#Override
public boolean onQueryTextChange(String newText) {
return true;
}
});
return true;
}
The doSearch() method:
private void doSearch(String query) {
//Log.e("Message :", "In the doSearch() method");
//Log.e("Message :", "The query in doSearh() is :" + query);
Iterator iterator = DatabaseOpenHelper.foodList.iterator();
while (iterator.hasNext()) {
Log.e("Message :", "In the while loop");
Food food = (Food) iterator.next();
if (food.getFoodName().equals(query)) {
dimContentBelow();
displayPopup(food);
}
}
}
The dim and undim methods:
private void dimContentBelow() {
constraintLayout.getForeground().setAlpha(100);
}
private void unDimContentBelow() {
constraintLayout.getForeground().setAlpha(0);
}
The displayPopup() method:
private void displayPopup(Food food) {
listFoodName.setText(food.getFoodName());
foodPic.setImageBitmap(food.getFoodPhoto());
popupWindow = new PopupWindow(popupView, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, false);
popupWindow.setElevation(5.0f);
popupWindow.showAtLocation(this.constraintLayout, Gravity.CENTER, 0, 0);
}
There's a acquirePopupChildren() method in which references are obtained to widgets in the popup window xml layout. One of the widgets is a close button which dismissed the popup and undims the content below:
ublic void acquirePopupChildren() {
listFoodName = (TextView) popupView.findViewById(R.id.list_food_name);
foodPic = (ImageView) popupView.findViewById(R.id.food_pic);
closeButton = (Button) popupView.findViewById(R.id.button_close);
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
unDimContentBelow();
popupWindow.dismiss();
}
});
}
I've also defined handleIntent() methods and onNewIntent() methods but I don't think they're being called because I've set a onTextSubmitListener() on the searchview which handles the search.

Android: SearchView setQuery does not set text on orientation change

I have SearchView which I want to programmatically expand and set text when the device orientation change. I tried many found solution but nothing work. If I use only setQuery then my list is filtered, but when I use also expandActionView then the search view does not contain the given search text and onQueryTextChange is called twice, first with the given text and the second time with the empty text.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.activity, menu);
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
MenuItem searchMenuItem = menu.findItem(R.id.search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem);
searchView.setIconifiedByDefault(true);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
searchView.setOnQueryTextListener(this);
MenuItemCompat.setOnActionExpandListener(searchMenuItem, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
mCurrentQueryString = null;
if (mAdapter != null) {
mAdapter.clearFilter();
mStopSearching = true;
}
return true;
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
if (mAdapter != null) {
mStopSearching = false;
}
return true;
}
});
mSearchView = searchView;
mSearchMenuItem = searchMenuItem;
mSearchView.post(new Runnable() {
#Override
public void run() {
MenuItemCompat.expandActionView(mSearchMenuItem);
mSearchView.setQuery(mCurrentQueryString, true);
}
});
super.onCreateOptionsMenu(menu, inflater);
}
I use the search view in the fragment which is used in the view pager. The fragment is retained. The problem is that onQueryTextChange function is called twice, by the second time with the empty text, but I am not sure why. This function is also called with the empty text when I first time open the search view when the fragment is initialized, but when close the serach view and open it again, this function is not called.
How can I fix it?
I've also faced that issue. The solution I've come up with was via posting with handler.
#Override public boolean onPrepareOptionsMenu(Menu menu) {
...
// SearchView doesn't retain it's state after orientation change
// have to handle it the bad way (╯°□°)╯︵ ┻━┻
boolean isQueryExists = !TextUtils.isEmpty(mSearchQuery);
if (isQueryExists) {
// Calling directly doesn't take effect
// Custom runnable class in order to refrain from context leakage
new Handler(Looper.getMainLooper()).post(new SearchMenuRunnable(mSearchView, mSearchQuery));
}
...
}
SearchMenuRunnable.java
public class SearchMenuRunnable implements Runnable {
private WeakReference<SearchView> mSearchViewWeakReference;
private String mSearchQuery;
public SearchMenuRunnable(SearchView searchView, String searchQuery) {
mSearchViewWeakReference = new WeakReference<>(searchView);
mSearchQuery = searchQuery;
}
#Override public void run() {
if (null != mSearchViewWeakReference.get()) {
SearchView searchView = mSearchViewWeakReference.get();
searchView.setIconified(false);
searchView.setQuery(mSearchQuery, true);
searchView.clearFocus();
}
}
This are source from one of projects in github. You can examine them here, it's pretty simple project.

How to let SearchView keep its last query content after reopen?

When using search view, I have a requirement from customer that they want to retain the search content after reopen the search view. My Search view is on a list view and do a real timing filtering based on what user input into the search box. When closed the search box by either click the back button on the phone or click the soft back button on the top left on action bar, the search box closed, search view iconfied. But when reopen it next time, the search query used last time is also been cleared, which I do not want.
My question is that is there a way I can keep the search view content there. Just hiding the search box, but not clear the content?
My related code are as follow:
MenuItem search;
SearchView searchView;
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_locationlist_fragment, menu);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
search = menu.findItem(R.id.action_search_location_list);
searchView = (SearchView) MenuItemCompat.getActionView(search);
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
searchView.setIconifiedByDefault(false);
searchView.setOnQueryTextListener(this);
searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
//This will make sure, when user closed search view, the list will be restored.
if(!hasFocus) {
Log.i(Tags.LOCATIONLIST,"Search Close");
search.collapseActionView();
} else {
}
}
}
});
ImageView closeButton = (ImageView)searchView.findViewById(R.id.search_close_btn);
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
EditText searchEditText = (EditText)searchView.findViewById(R.id.search_src_text);
searchEditText.setText("");
if (((LocationListAdapter)locationListView.getAdapter())!=null) {
((LocationListAdapter) locationListView.getAdapter()).getFilter().filter("");
}
}
});
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_search_location_list:
((BaseActivity) getActivity()).onSearchRequested();
return true;
case R.id.action_refresh_location_list:
refreshLocationList();
return true;
default:
return false;
}
}
#Override
public boolean onQueryTextSubmit(String s) {
return false;
}
#Override
public boolean onQueryTextChange(String s) {
if (((LocationListAdapter)locationListView.getAdapter())!=null) {
if (TextUtils.isEmpty(s)) {
locationListView.clearTextFilter();
} else {
((LocationListAdapter) locationListView.getAdapter()).getFilter().filter(s);
//locationListView.setFilterText(s.toString());
}
}
return true;
}
Use
SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setIconified(false);
Any query text is cleared when iconified. So setIconified to false. And i have used android.widget.SearchView
Save your String in a variable (e.g. myWantedString) and
override setOnClickListener that trigers everytime you open the SearchView and use setQuery. Your code should be:
searchView.setOnSearchClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
searchView.setQuery(myWantedString, false);
}
});
To save your string each time the SearchView closes implement setOnCloseListener and override onClose():
searchView.setOnCloseListener(new SearchView.OnCloseListener()
{
#Override
public boolean onClose()
{
myWantedString = searchView.getQuery();
return false;
}
});
searchView.setQuery() works if was called with a delay after menu item expansion.
MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(item);
// set query text with a delay
searchView.post(new Runnable() {
#Override
public void run() {
searchView.setQuery(query, false);
}
});
return true;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return true;
}
});
You can create an Activity which can be called when the user searches and the search result can be stored in the Bundle during the callback method onPause or onSaveInstanceState , when the Activity is called once again restore it from the bundle.
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setIconified(false);
searchView.setOnSearchClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
searchView.setQuery("SEARCH_WORD", false);
}
});
https://developer.android.com/reference/android/widget/SearchView
Sets a listener to inform when the search button is pressed. This is only relevant when the text field is not visible by default. Calling setIconified(false) can also cause this listener to be informed.

How do I capture SearchView's clear button click?

How can I capture the event of user click on clear SearchView text by clicking on the X button on the right
I already captured onQueryTextChange event but, this is for any text change not for that X button
After trying a lot of combinations, I found how to capture the event behind the X button in SearchView
Below is a code snippet from onCreateOptionsMenu function in one of my apps. mSearchMenu and mSearchView are global variables.
The X is actually an ImageView with ID search_close_btn and the text area is an EditText view with ID search_src_text
#SuppressLint("NewApi")
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.country_list_activity_actions, menu);
mSearchMenu = menu.findItem(R.id.action_search);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// Get the SearchView and set the searchable configuration
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
mSearchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
// Assumes current activity is the searchable activity
mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
mSearchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
// Get the search close button image view
ImageView closeButton = (ImageView)mSearchView.findViewById(R.id.search_close_btn);
// Set on click listener
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LoggerUtils.d(LOG, "Search close button clicked");
//Find EditText view
EditText et = (EditText) findViewById(R.id.search_src_text);
//Clear the text from EditText view
et.setText("");
//Clear query
mSearchView.setQuery("", false);
//Collapse the action view
mSearchView.onActionViewCollapsed();
//Collapse the search widget
mSearchMenu.collapseActionView();
}
});
}
// When using the support library, the setOnActionExpandListener() method is
// static and accepts the MenuItem object as an argument
mSearchMenu.setOnActionExpandListener(new OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
//Nothing to do here
LoggerUtils.d(LOG, "Search widget expand ");
return true; // Return true to expand action view
}
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
LoggerUtils.d(LOG, "Search widget colapsed ");
return true; // Return true to collapse action view
}
});
return super.onCreateOptionsMenu(menu);
}
you can just use the onCloseListener()
sv= (SearchView) findViewById(R.id.searchView1);
sv.setOnCloseListener(new OnCloseListener() {
#Override
public boolean onClose() {
Toast t = Toast.makeText(MainActivity.this, "close", Toast.LENGTH_SHORT);
t.show();
return false;
}
});
I had problems trying to find the component by its ID but I found another way to search this component using the context of the same SearchView
// Catch event on [x] button inside search view
int searchCloseButtonId = searchView.getContext().getResources()
.getIdentifier("android:id/search_close_btn", null, null);
ImageView closeButton = (ImageView) this.searchView.findViewById(searchCloseButtonId);
// Set on click listener
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Manage this event.
}
});
I use this code to catch text query clearing, and perform my actions
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.search, menu);
SearchView searchView = (SearchView) menu.findItem(R.id.search_button).getActionView();
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
SearchView.OnQueryTextListener textChangeListener = new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextChange(String cs) {
if (TextUtils.isEmpty(cs)){
//Text is cleared, do your thing
}
return false;
}
#Override
public boolean onQueryTextSubmit(String query) {
//text query submitted
}
};
searchView.setOnQueryTextListener(textChangeListener);
return true;
}
If you use Appcompat library, instead of using
getResources().getIdentifier("android:id/search_close_btn", null, null);
you can do this:
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
View closeButton = searchView.findViewById(android.support.v7.appcompat.R.id.search_close_btn);
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//handle click
}
});
EDIT AUGUST 2019:
If you use androidx: androidx.appcompat.R.id.search_close_btn
If you are using the SearchView from androidx, you can do this:
val closeButton: View? = searchView.findViewById(androidx.appcompat.R.id.search_close_btn)
closeButton?.setOnClickListener {
//TODO: Set your action
}
ImageView closeButton = (ImageView) this.searchView.findViewById(android.support.v7.appcompat.R.id.search_close_btn);
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Manage this event.
}
});
Use R.id.search_go_btn for "Submit" Button
A kotlin answer:
mySearchView.setOnCloseListener(object : SearchView.OnCloseListener {
override fun onClose(): Boolean {
// Do your stuff
return false
}
})
The solution from Eduardo doesnt work for me. I found something else which is working for Kotlin. I found this solution thanks to SjoerdvGestel and it's answer.
// Get the close button on the searchView
val closeButtonId: Int = searching.context.resources.getIdentifier("android:id/search_close_btn", null, null)
val closeButton = searching.findViewById(closeButtonId) as ImageView
// On close collapse the searchView
closeButton.setOnClickListener {
searching.onActionViewCollapsed()
true
}
To return to the initial state of the SearchView, you can make a clear focus when the "X" is pressed, in addition, this clear focus hides the keyboard.
searchview.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
searchview.clearFocus();
return false;
}
});
I got this answer by checking the androidx.appcompat.widget.SearchView class and checked for the id close button and found ImageView mCloseButton = findViewById(R.id.search_close_btn); So the solution is to get the reference of this id in your searchView implementation and attach onClickListener to it. So what internally happens is that we are overriding the imageView's setOnClickListener and adding our implementation. Here is the code.
SearchView searchView = findViewById(R.id.search_view);
ImageView closeButton = searchView.findViewById(R.id.search_close_btn);
if (closeButton != null) closeButton.setOnClickListener(v -> {
//your logic goes in here
});
A kotlin clean & simple answer using (Lambda):
mySearchView.setOnCloseListener {
// Do your stuff
return false
}
This is the code that worked for me:
ImageView closeButton = (ImageView) this.searchView.findViewById(androidx.appcompat.R.id.search_close_btn);
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//DO SMTH
}
});

Auto Collapse ActionBar SearchView on Soft Keyboard close

I am currently using an ActionBar menu item to display a SearchView in the action bar. When the search menu item is expanded the soft keyboard is displayed which is what I want. Now, when the user presses the back button to close the soft keyboard, I would also like to collapse the SearchView in the action bar.
I have tried implementing the following listeners OnKeyListener and OnFocusChangeListener on the MenuItem and the ActionView. I have also tried using OnBackPressed() in the Activity. None of the above detect when the back button is used to close the soft keyboard.
Any ideas?
I have implemented OnActionExpandListener to know when the SearchView is visible.
I'll expand on #user1258568 's answer for the lazy. This worked for me. Note that it clears your query when focus is lost.
final MenuItem searchMenuItem = optionsMenu.findItem(R.id.search);
final SearchView searchView = (SearchView) searchMenuItem.getActionView();
searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View view, boolean queryTextFocused) {
if(!queryTextFocused) {
searchMenuItem.collapseActionView();
searchView.setQuery("", false);
}
}
});
I found a better solution.
searchView.setOnQueryTextFocusChangeListener().
The OnQueryTextFocusChangeListener gets called when the keyboard is displayed or hidden. Gets called first when the keyboard is displayed and the search view will have focus. Gets called again when keyboard is hidden and search view will lose focus, can close search viewthen using
menuItem.collapseActionView().
Just Override onBackPressed like this:
#Override
public void onBackPressed() {
if (searchView.isShown()){
searchView.onActionViewCollapsed(); //collapse your ActionView
searchView.setQuery("",false); //clears your query without submit
isClosed = true; //needed to handle closed by back
} else{
super.onBackPressed();
}
}
and your onCreateOptionsMenu would inflate the mSearchView like this:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_search, menu);
mSearchView = (SearchView) menu.findItem(R.id.menu_action_search).getActionView();
mSearchView.setOnQueryTextListener(this);
mSearchView.setOnSearchClickListener(this);
mSearchView.setOnCloseListener(this);
isClosed = true;
return true;
}
have you class implement the following like this:
public class myActivity extends FragmentActivity implements
SearchView.OnQueryTextListener, View.OnClickListener, SearchView.OnCloseListener {
which you will also need:
#Override
public void onClick(View view) {
isClosed = false;
}
#Override
public boolean onClose() {
isClosed = true;
return false;
}
You will need to make "mSearchView" and "isClosed" both global variables to the activity.
The answer from Jon Willis works great. This is an improvement to his answer.
First, create a new class that implements View.OnFocusChangeListener:
public class SearchViewFocusListener implements View.OnFocusChangeListener {
private final MenuItem mMenuItem;
public SearchViewFocusListener(MenuItem menuItem) {
mMenuItem = menuItem;
}
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
mMenuItem.collapseActionView();
if (v instanceof SearchView) {
((SearchView) v).setQuery("", false);
}
}
}
}
Next, set the listener on your SearchView:
searchView.setOnQueryTextFocusChangeListener(new SearchViewFocusListener(menuItem));
You only need to put the "collapseActionView" attribute in the menu layout
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/menu_item_search"
android:title="#string/search"
android:iconifiedByDefault="true"
android:icon="#drawable/ic_action_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView"/> <--this one
</menu>
That will give you the functionality you look for all by itself.Don't forget to call the method "clearFocus" on the SearchView to close the keyboard once you send the query.
This is what I did for making the keyboard disappear. You can try to see if this works for you. I set the searchView to invisible and then to visible again.
//set query change listener
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
#Override
public boolean onQueryTextChange(String newText) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onQueryTextSubmit(String query) {
/**
* hides and then unhides search tab to make sure keyboard disappears when query is submitted
*/
searchView.setVisibility(View.INVISIBLE);
searchView.setVisibility(View.VISIBLE);
return false;
}
});
It's achievable like this:
private void setupSearchView(Menu menu) {
final MenuItem searchMenuItem = menu.findItem(R.id.action_search);
final SearchView searchView = (SearchView) searchMenuItem.getActionView();
[...]
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
searchMenuItem.collapseActionView();
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
return true;
}
});
}
Solutions based on setOnQueryTextFocusChangeListener() did not work for me because the event was not launched - the searchView did not lose focus when submitted, probably because I perform the search in the same activity that contains the Search View.
Anyway, I think using OnQueryTextListener is more correct, as it describes the event of submitting text more precisely.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.home_screen, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
final MenuItem searchMenuItem = menu.findItem(R.id.menu_search);
final SearchView searchView = (SearchView) searchMenuItem
.getActionView();
searchView.setIconifiedByDefault(false);
if (searchManager != null && searchView != null) {
searchView.setSearchableInfo(searchManager
.getSearchableInfo(getComponentName()));
searchView
.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
if (searchMenuItem != null) {
searchMenuItem.collapseActionView();
}// end if
if (searchView != null) {
searchView.setQuery("", false);
}// end if
}// end if
}
});
searchView
.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
/**
* hides and then unhides search tab to make sure
* keyboard disappears when query is submitted
*/
if (searchView != null) {
searchView.setVisibility(View.INVISIBLE);
searchView.setVisibility(View.VISIBLE);
}
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
// TODO Auto-generated method stub
return false;
}
});
}
return super.onCreateOptionsMenu(menu);
}
If you want to collapse keyboard when user clicks search icon on keyboard
this can be achieved by simple
inside onquerytextsubmitted {
searchView.clearfocus()
}
You need to call setIconified twice.
To actually collapse your search view and close the keyboard.
With first call text of search view is cleared with second call keyboard and search view get closed.
For some reason, menuItem.collapseActionView() did not work so I used searchView.setIconified(true) instead.
This gives the below result as the code sample.
final MenuItem searchItem = (MenuItem) menu.findItem(R.id.menu_item_search);
final SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setOnQueryTextFocusChangeListener(new SearchView.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
searchView.setIconified(true);
}
}
});

Categories

Resources