I have an interesting problem - though maybe it is the expected behavior? I have a SearchView in my tool bar, which functions just fine till I enter a search then close it, at which time the search icon disappears and the ability to do another search is lost.
This behavior only happens when the search query is initiated - so if I enter search text, clear the search, then close it, the icon is there. But if I close it with data in it, then the Icon disappears. It is not the text color - I have clicked away and nothing seems to be there.
Here are some pictures of what I am talking about:
Search is there:
Enter search, query:
Close SearchView, icon gone
Menu:
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/library_forms_refresh"
android:orderInCategory="100"
android:showAsAction="always|withText"
android:icon="#drawable/ic_action_refresh"
android:title="refresh"/>
</menu>
The code looks like this:
import android.widget.SearchView;
#Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
menu.clear();
mMenu = menu; // remember so we can get to later.
inflater.inflate(R.menu.library_forms, menu);
(removed some code not related to this)
// Implementing ActionBar Search inside a fragment
MenuItem item = menu.add("Search");
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
sv = new SearchView(getActivity());
// If we are on a Phone, make the search an icon, otherwise show it all
if (GlobalState.getInstance().isTwoPane == true) {
sv.setIconifiedByDefault(false);
}
else {
sv.setIconifiedByDefault(true);
}
sv.setFocusable(false);
// modifying the text inside edit text component
int id = sv.getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
TextView textView = (TextView) sv.findViewById(id);
textView.setHint("Form or Reference Number");
textView.setHintTextColor(Color.WHITE);
textView.setTextColor(Color.WHITE);
// Change the Icon color
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int searchButtonId = sv.getContext().getResources().getIdentifier("android:id/search_button", null, null);
ImageView searchButton = (ImageView) sv.findViewById(searchButtonId);
searchButton.setImageTintList(ColorStateList.valueOf(Color.WHITE));
}
// implementing the listener
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
Handler handler = new Handler();
#Override
public boolean onQueryTextSubmit(String s) {
handler.removeCallbacksAndMessages(null);
if (s != null && s.trim().length() > 0)
{
searchFilter = s;
// Delay the lookup by 800 ms
handler.postDelayed(new Runnable() {
#Override
public void run() {
// do some stuff here...
}
}, 800);
}
return true;
}
#Override
public boolean onQueryTextChange(String newText) {
// If the string is empty, reload the form
if (newText == null || newText.trim().length() == 0)
{
searchFilter = null;
// do some stuff here...
// Hides the soft keyboard
sv.setVisibility(View.INVISIBLE);
sv.setVisibility(View.GONE);
}
else {
onQueryTextSubmit(newText);
}
return true;
}
});
item.setActionView(sv);
}
The problem was this code:
// do some stuff here...
// Hides the soft keyboard
sv.setVisibility(View.INVISIBLE);
sv.setVisibility(View.GONE);
Which hid the keyboard and the icon.
Related
Well, what I want is to:
Initialize ActionBar with all items, except "searchSettings";
When click on the Search icon, searchSettings appears and the rest of the icons disappear;
When close the search EditText (pressing device's back button or ActionBar's back button), ActionBar returns to its original state (all icons appearing, except "searchSettings").
My actual code is the following:
(I've imported android.support.v7.widget.SearchView instead of android.widget.SearchView. When I was using android.widget.SearchView this worked fine but other things don't)
private MenuItem searchIteam, searchSettings;
private SearchView searchView;
#Override
public boolean onCreateOptionsMenu(final Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, menuMain);
searchItem = menu.findItem(R.id.search);
searchSettings = menu.findItem(R.id.action_searchSettings);
searchView = (SearchView)MenuItemCompat.getActionView(item);
searchSettings.setVisible(false); // hide searchSettings Item when Menu is created
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
(...)
return false;
}
});
// Detect SearchView icon clicks
searchView.setOnSearchClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setItemsVisibility(menuMain, item, false);
searchSettings.setVisible(true);
}
});
// Detect SearchView close
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
supportInvalidateOptionsMenu(); //shouldn't this reload the Action Bar as it was when onCreate?
return true;
}
});
return super.onCreateOptionsMenu(menu);
}
private void setItemsVisibility(Menu menu, MenuItem exception, boolean visible) {
for (int i=0; i<menu.size(); ++i) {
MenuItem item = menu.getItem(i);
if (item != exception) item.setVisible(visible);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
supportInvalidadeOptionsMenu();
super.onBackPressed();
}
This code doesn't work, when I press "back" first time, it only closes the Search's EditText and the icons don't change. If I press back again, the Activity goes a level up but I can see the icons getting as the beginning (getting as they should when I pressed "back" for the first time) a little while before the Activity close...
--- EDIT ---
Currently, if I click on Search ActionBar Icon, and then begin to press "Back Button" repeatedly, the following happens:
1st pressing: the keyboard hides, but the search EditText is still open;
2nd pressing: the searching ends (search EditText closes and the normal activity's content is shown);
3rd pressing: the activity closes.
Then, for testing purposes, I did this:
boolean pressed1, pressed2, pressed3;
searchView.setOnSearchClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pressed1 = false;
pressed2 = false;
pressed3 = false;
setItemsVisibility(menuMain, item, false);
searchSettings.setVisible(true);
}
});
#Override
public void onBackPressed() {
if (!pressed1) {
pressed1 = true;
}
else if(!pressed2) {
pressed2 = true;
}
else if(!pressed3) {
pressed3 = true;
supportInvalidateOptionsMenu();
}
else {
super.onBackPressed();
}
}
And now, what happens is:
1st pressing: the keyboard hides, but the search EditText is still open;
2nd pressing: the searching ends (search EditText closes and the normal activity's content is shown);
3rd pressing: nothing happens;
4th pressing: nothing happens;
5th pressing: the ActionBar reloads as I wanted;
6th pressing: the activity closes;
--- EDIT 2 ---
Then I've changed to this:
#Override
public void onBackPressed() {
if (!pressed1) {
pressed1 = true;
onBackPressed();
}
else if(!pressed2){
pressed2 = true;
onBackPressed();
}
else if(!pressed3){
pressed3 = true;
supportInvalidateOptionsMenu();
}
else {
super.onBackPressed();
}
}
What is happening now is:
1st pressing: the keyboard hides, but the search EditText is still open;
2nd pressing: the searching ends (search EditText closes and the normal activity's content is shown);
3rd pressing: the ActionBar reloads as I wanted;
4th pressing: the activity closes;
--- EDIT 3 --- (SOLUTION) ---
I guess that the methods setOnSearchClickListener and setOnCloseListener are from android.widget.SearchView... As I've imported android.support.v7.widget.SearchView instead, I've changed them to:
MenuItemCompat.setOnActionExpandListener(searchItem,
new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem menuItem) {
setItemsVisibility(menu, searchItem, false);
return true;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem menuItem) {
supportInvalidateOptionsMenu();
return true;
}
});
Now it's working just fine (:
I hope I get you right: the first time you press BACK, the keyboard gets hidden. The second time you press BACK, the app quits.
If this is the case, then everything works fine. Becuase this is what super.onBackPressed() is supposed to do. It will try to hide the keyboard if it's shown. If not, it will try to go the previous activity. If there is none, it will quit the app.
So what you need to do is play with the onBackPressed() method. Basically, you don't necessarily need to call the super method if you are sure what you should do.
#Override
public void onBackPressed() {
if ( isSearching) {
supportInvalidadeOptionsMenu();
isSearching = false;
} else {
super.onBackPressed();
}
}
So now, when never you press BACK button, the activity will check if isSearching, and decide to re-render the action bar or take its normal actions as usual.
You'll need to add some logic to set the boolean flag isSearching, for example, set isSearching to true when clicking the Search.
I 'm not sure if supportInvalidadeOptionsMenu() would reset your action bar. Anyway, you can adjust the visibility for each view instead.
I have an EditText in expandable action view in Toolbar. When I expand the action, the EditText is shown and I want it to get focus. To achieve that I do following:
action_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/connections_find_people_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<EditText
android:id="#+id/connections_find_people_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"/>
</RelativeLayout>
In my fragment
#Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.add_connection, menu);
mAddMenuItem = menu.findItem(R.id.menu_add);
MenuItemCompat.setActionView(mAddMenuItem, R.layout.action_layout);
mSearchView = MenuItemCompat.getActionView(mAddMenuItem);
mSearchEditText = (EditText) mSearchView.findViewById(R.id.connections_find_people_edit);
MenuItemCompat.setOnActionExpandListener(mAddMenuItem, mOnSearchExpandListener);
super.onCreateOptionsMenu(menu, inflater);
}
private final OnSearchExpandListener mOnSearchExpandListener = new MenuItemCompat.OnActionExpandListener {
mSearchEditText.requestFocus();
return true;
}
#Override
public boolean onMenuItemActionCollapse(final MenuItem item) {
return true;
}
}
Surprisingly, this does not work. After tapping the action in toolbar, the view expands, mSearchEditText is shown, but doesn't get focus.
More specifically (and weirdly), mSearchEditText.requestFocus(); returns true, but software keyboard is still not shown and there is no cursor in mSearchEditText.
Showing software keyboard is not a big deal, there are ways to force it, but even when I show the keyboard, typing doesn't insert any text into mSearchEditText. It's only after I tap on mSearchEditText when cursor appears and I can type some text in it.
What I've tried:
Setting focusable and focusableInTouchMode both in XML and programatically and both in onCreateOptionsMenu() and when the action view is expanded
Clearing focus before requesting it like mSearchEditText.clearFocus()
Delaying requestFocus() after the view expands
It's really weird, because following
#Override
public boolean onMenuItemActionExpand(final MenuItem item) {
mSearchEditText.setFocusableInTouchMode(true);
mSearchEditText.setFocusable(true);
mSearchView.postDelayed(new Runnable() {
#Override
public void run() {
if (mSearchEditText.requestFocus()) {
KeyboardUtils.showSoftKeyboard(ConnectionsFragment.this);
}
}
}, 300);
return true;
}
shows the keyboard, which should mean mSearchEditText has focus, but typing doesn't enter any text. (Again, when I tap on the EditText, cursor appears and everything works fine).
Aaand as it happens sometimes, soon after posting the question I found the answer myself.
Instead of getting reference to the EditText in onCreateOptionsMenu() I had to use the MenuItem passed to onMenuItemActionExpand() and get the reference there.
So this now works for me:
#Override
public boolean onMenuItemActionExpand(final MenuItem item) {
final View actionView = MenuItemCompat.getActionView(item);
final View edit = actionView.findViewById(R.id.connections_find_people_edit);
if(edit.requestFocus()) {
KeyboardUtils.showSoftKeyboard(ConnectionsFragment.this);
}
return true;
}
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:
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)
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()));
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;
}
I have an item in my actionbar that shows a progressbar when clicked. However, when the user clicks the progressbar, I want the progress bar to stop, and show the normal "refresh" button again. Currently the progressbar become unclickable. Here's my code:
case R.id.id_Refresh:;
menuItem = item;
if(btnRefreshPressed == true){
menuItem.setActionView(R.layout.progressbar);
menuItem.expandActionView();
btnRefreshPressed = false;
mUpdateMap.run();
return true;
}else if(btnRefreshPressed == false){
menuItem.collapseActionView();
menuItem.setActionView(null);
mHandler.removeCallbacks(mUpdateMap);
btnRefreshPressed = true;
return true;
}
progressbar.xml:
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/progressbar2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true" >
</ProgressBar>
when you use your own actionView, you need to handle the clicking on the view itself:
menuItem.getActionView().setOnClickListener(...);
also, instead of having 2 modes , one with actionView and another without, you can use viewSwitcher as the actionView , and just toggle it when you want , by using showNext().
EDIT: for easiest way to support clicking on action bar items, no matter if they contain an actionView or not, you can use this code:
public static void setOnMenuItemSelected(final MenuItem menuItem, final Runnable runnable) {
final View view = menuItem.getActionView();
if (view != null)
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
runnable.run();
}
});
else
menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(final MenuItem item) {
runnable.run();
return true;
}
});
}
You are not passing in the ID:
findViewById(com.example.androidbasic12.R.layout.progressbar);
it should be R.id.YourID not R.layout.progressbar
That's why you get a NullPointerException
We've got a SearchView on the ActionBar which is set to be non-iconified. As we don't have any content in the view until the user's entered something to search for, it would make sense to give the SearchView initial focus, and make sure the soft keyboard is showing ready for the user to enter text — otherwise they'll always have to first tap in the SearchView.
I can give the SearchView focus by just calling
searchView.requestFocus();
but I can't get the soft keyboard to appear. In another one of our Fragments I have an EditText which we want to be focused I can get the soft keyboard to appear there by calling
InputMethodManager mgr = (InputMethodManager)getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE);
mgr.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
but this just doesn't work on the SearchView. It must surely be possible to get this to work.
Further rummaging around StackOverflow and I found this question:
Forcing the Soft Keyboard open
which contains a solution that worked for me:
((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE)).
toggleSoftInput(InputMethodManager.SHOW_FORCED,
InputMethodManager.HIDE_IMPLICIT_ONLY);
I have a similar problem where none of the proposed solutions here worked. Some just didn't make the keyboard appear at all and some show a keyboard but the key presses there just do not work.
The only thing that worked was:
// hack for making the keyboard appear
searchView.setIconified(true);
searchView.setIconified(false);
I am using a SearchView with setIconifiedByDefault(false). Testing with Android 4.4.2, the only way I could get the keyboard to actually show was to look at the source code for SearchView and mimic how it requested the keyboard to be shown. I've tried literally every other method I could find/think of and this is the only way I could get the keyboard to show reliably. Unfortunately, my method requires some reflection.
In onCreateOptionsMenu(Menu):
searchView.requestFocus();
searchView.post(new Runnable() {
#Override
public void run() {
showSoftInputUnchecked();
}
});
And then create a method to call the hidden method "showSoftInputUnchecked" in InputMethodManager:
private void showSoftInputUnchecked() {
InputMethodManager imm = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
Method showSoftInputUnchecked = null;
try {
showSoftInputUnchecked = imm.getClass()
.getMethod("showSoftInputUnchecked", int.class, ResultReceiver.class);
} catch (NoSuchMethodException e) {
// Log something
}
if (showSoftInputUnchecked != null) {
try {
showSoftInputUnchecked.invoke(imm, 0, null);
} catch (IllegalAccessException e) {
// Log something
} catch (InvocationTargetException e) {
// Log something
}
}
}
}
As with all solutions that access methods not in the public API, I can't promise that this won't break with new versions of Android.
It worked for me.
private SearchView mSearchView;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
MenuItem searchItem = menu.findItem(R.id.action_search);
mSearchView =
(SearchView) searchItem.getActionView();
mSearchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_search) {
mSearchView.setIconifiedByDefault(true);
mSearchView.setFocusable(true);
mSearchView.setIconified(false);
mSearchView.requestFocusFromTouch();
}
return super.onOptionsItemSelected(item);
}
If you wanna show the soft keyboard and focus on the input box, you can try
final MenuItem menuItem = menu.findItem(R.id.action_search);
menuItem.expandActionView();//expand show soft keyboard
<item
android:id="#+id/action_search"
android:icon="#drawable/ic_actionbar_search"
liven:showAsAction="collapseActionView|always" //always
liven:actionViewClass="android.support.v7.widget.SearchView" />enter code here
This will not show keyboard every time you come on activity
searchview.clearFocus();
Use expandView method :
Your onCreateOptionsMenu could be something like this:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//Used to put dark icons on light action bar
final SearchView searchView = new SearchView(getSupportActionBar().getThemedContext());
MenuItem mitem = menu.add("Search");
mitem.setIcon(ic_search_inverse)
.setActionView(searchView)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
mitem.expandActionView();
listsearch.setOnItemClickListener(this);
return true;
}
You can try what I did. This worked well for me.
//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
* 4 = INVISIBLE
* 0 = VISIBLE
*/
searchView.setVisibility(4);
searchView.setVisibility(0);
return false;
}
});