How to handle ActionBar's icons visibility when using SearchView - android

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.

Related

How to hide ActionPopupWindow of Text Selection Handler of EditText

Actually I want to hide ActionPopupWindow (popup having SELECT ALL, CLIPBOARD options) when user click on + icon(refer to the attached image).
ActionPopupWindow appears when user click on the Text Selection Handler(bubble) (which appears when user tap on the text in the EditText).
I have tried to use setTextIsSelectable() method of EditText but it is not working consistently.
Any help or guidance will be well appreciated.
UPDATE: To hide the Popup already opened and showing on the screen, you need to clear focus of the current EditText or focus on other view when you clicked the plus button. See the
example below:
iconPlus.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
yourEditText.clearFocus();
}
});
If you want the popup never shows up at the first place, there are many ways to do it.
The simplest way is disabling long click and selection feature:
yourEditText.setLongClickable(false);
yourEditText.setTextIsSelectable(false);
Second one is overriding action callback actions on your edittext:
yourEditText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
public void onDestroyActionMode(ActionMode mode) {
}
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
You can use them separately or together according to your case.
Also you can check other options from here

disable menu hiding on searchview search

when I use searchview, when searchview is active it hides menu icon , but i need this menu when search active also. How prevnt it from hiding?
After searching it hides the red colored menu
if you don't want sort menu in search, you can hide it on searchview expand. If you will hide sort menu, option menu will stay exists.
Here is example
final MenuItem sortmenu = menu.findItem(R.id.action_sort);
searchView.setOnCloseListener(new android.support.v7.widget.SearchView.OnCloseListener() {
#Override
public boolean onClose() {
sortmenu.setVisible(true);
invalidateOptionsMenu();
return false;
}
});
searchView.setOnSearchClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sortmenu.setVisible(false);
}
});

SearchView does not respond to clicks after query submit

My app contains a standard SearchView widget. As you can see from the code below, I am setting an OnClickListener, an OnCloseListener, and an OnQueryTextListener.
If I tap the SearchView, it initially responds as expected. If I enter text and press the search button the keyboard, the OnQueryTextListener fires correctly, and the keyboard is dismissed as per searchView.setIconified(true). However, if I now tap the SearchView again, the OnClickListener is not fired. The keyboard still appears and the field becomes editable, but my code in the OnClickListener is not executed.
If I use the "X" icon to close the search view after this, everything returns to normal. The next time I click on the SearchView, my listener is fired.
I have additional code that I'll need to execute every time the SearchView is clicked.
What could be causing the listener to not fire in this specific instance? Is there something else that I should be doing in OnQueryTextSubmit?
searchView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
filterLayout.setVisibility(View.VISIBLE);
searchView.setIconified(false);
System.out.println("on click");
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
#Override
public boolean onClose() {
filterLayout.setVisibility(View.INVISIBLE);
return false;
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
searchView.setIconified(true);
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
return false;
}
});
I found a half-answer to this problem. If I clear the focus of the searchView when the query is submitted, then when the user next taps the searchView, the OnQueryTextFocusChangeListener gets a call. It doesn't exactly answer my original question, but it's an acceptable workaround for my case.

Remove CAB but preserve webview text selection

I want to implement my own custom view (not inflating a menu item), I'm planning to use a toolbar to appear each time contextMenu starts, and hide it when finished.
the problem is: there are only answer showing HOW to clear/inflate another menu over the default actionMode menu
what i`ve tried so far:
-> Use a custom contextual action bar for WebView text selection
Overriding the callback at the WebView
#Override
public ActionMode startActionMode(ActionMode.Callback callback) {
callback2 = new customCallBack();
return super.startActionMode(callback2);
}
public class customCallBack implements ActionMode.Callback {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
}
changing the return false to true, doesn't result in the desired behavior i.e. hide the cab
Overriding the OnLongClick is not a option too, since it disable the current selection.
This answer solves the problem:
android webview: prevent text selection actionMode actionBar
not the most elegant solution ever, but I just tested it in an app I'm building and it works like a charm.
The Only way that worked for me (only on on Android L+) is clearing all the menu items from context actionbar from the activity
#Override
public void onActionModeStarted(ActionMode mode) {
if (mActionMode == null) {
mActionMode = mode;
Menu menu = mode.getMenu();
// Remove the default menu items (select all, copy, paste, search)
menu.clear();
}
Toast.makeText(this, "onActionModeStarted", Toast.LENGTH_SHORT).show();
super.onActionModeStarted(mode);
}
#Override
public void onActionModeFinished(ActionMode mode) {
mActionMode = null;
Toast.makeText(this, "onActionModeFinished", Toast.LENGTH_SHORT).show();
super.onActionModeFinished(mode);
}
inspired by Use a custom contextual action bar for WebView text selection
Also I wasn't able to implement the custom menu usin popupWindow or dialogs or dialog fragments.
So simply put it with the webView in a frame layout and play with its visability and margin

Use a custom contextual action bar for WebView text selection

I have used this guide from Google and this tutorial to produce my own contextual action bar.
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.annotation_menu, menu);
return true;
}
// Called each time the action mode is shown.
// Always called after onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.custom_button:
// do some stuff
break;
case R.id.custom_button2:
// do some other stuff
break;
default:
// This essentially acts as a catch statement
// If none of the other cases are true, return false
// because the action was not handled
return false;
}
finish(); // An action was handled, so close the CAB
return true;
}
// Called when the user exits the action mode
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
This menu is designed to appear when the user selects text, so it overrides the native copy/paste menu. Now I get to my issue.
Because I am overriding functions for text selection, I also added a LongClickListener to a WebView and implemented the onLongClick(View v) method so I can detect when users make the selection.
myWebView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActionMode != null) {
return false;
}
mActionMode = startActionMode(mActionModeCallback);
v.setSelected(true);
return true;
}
});
When I long click, I see my custom menu appear, but no text is highlighted.I need to have the text selection functionality; without it, my menu is pointless.
How do I override onLongClick(View v), but maintain the text selection provided by Android?If that is not possible, can I make the call to startActionMode(mActionModeCallback) somewhere else so that text will be selected as normal, but my custom menu will also appear?If neither of those are possible... help.
THERE IS AN EASIER WAY! See update below :D
For the sake of completeness, here is how I fixed the problem:
I followed the suggestion according to this answer, with a little more tweaking to more closely match the overridden code:
public class MyWebView extends WebView {
private ActionMode mActionMode;
private mActionMode.Callback mActionModeCallback;
#Override
public ActionMode startActionMode(Callback callback) {
ViewParent parent = getParent();
if (parent == null) {
return null;
}
mActionModeCallback = new CustomActionModeCallback();
return parent.startActionModeForChild(this, mActionModeCallback);
}
}
Essentially, this forces your customized CAB to appear instead of the Android CAB. Now you have to modify your callback so that the text highlight will go away along with the CAB:
public class MyWebView extends WebView {
...
private class CustomActionModeCallback implements ActionMode.Callback {
...
// Everything up to this point is the same as in the question
// Called when the user exits the action mode
#Override
public void onDestroyActionMode(ActionMode mode) {
clearFocus(); // This is the new code to remove the text highlight
mActionMode = null;
}
}
}
That's all there is to it. Be aware that as long as you are using MyWebView with the overridden startActionMode there is NO WAY to get the native CAB (the copy/paste menu, in the case of a WebView). It may be possible to implement that sort of behavior, but that is not the way this code works.
UPDATE: There is a much easier way to do this! The above solution works well, but here is an alternative, easier way.
This solution provides less control over the ActionMode, but it requires far less code than the above solution.
public class MyActivity extends Activity {
private ActionMode mActionMode = null;
#Override
public void onActionModeStarted(ActionMode mode) {
if (mActionMode == null) {
mActionMode = mode;
Menu menu = mode.getMenu();
// Remove the default menu items (select all, copy, paste, search)
menu.clear();
// If you want to keep any of the defaults,
// remove the items you don't want individually:
// menu.removeItem(android.R.id.[id_of_item_to_remove])
// Inflate your own menu items
mode.getMenuInflater().inflate(R.menu.my_custom_menu, menu);
}
super.onActionModeStarted(mode);
}
// This method is what you should set as your item's onClick
// <item android:onClick="onContextualMenuItemClicked" />
public void onContextualMenuItemClicked(MenuItem item) {
switch (item.getItemId()) {
case R.id.example_item_1:
// do some stuff
break;
case R.id.example_item_2:
// do some different stuff
break;
default:
// ...
break;
}
// This will likely always be true, but check it anyway, just in case
if (mActionMode != null) {
mActionMode.finish();
}
}
#Override
public void onActionModeFinished(ActionMode mode) {
mActionMode = null;
super.onActionModeFinished(mode);
}
}
Here is an example Menu to get you started:
<!-- my_custom_menu.xml -->
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/example_item_1"
android:icon="#drawable/ic_menu_example_1"
android:showAsAction="always"
android:onClick="onContextualMenuItemClicked"
android:title="#string/example_1">
</item>
<item
android:id="#+id/example_item_2"
android:icon="#drawable/ic_menu_example_2"
android:showAsAction="ifRoom"
android:onClick="onContextualMenuItemClicked"
android:title="#string/example_2">
</item>
</menu>
That's it! You're done! Now your custom menu will show up, you don't have to worry about the selection, and you barely have to concern yourself with the ActionMode lifecycle.
This works nearly flawlessly with a WebView that occupies its entire parent Activity. I am not sure how well it will work if there are multiple Views within your Activity at one time. It will likely require some tweaking in that case.
The way I did something similar was to only override the onTouchListener and to invoke a GestureDetector to detect when the WebView was long-pressed and do what I wanted from there. Here's some sample code that allows you to catch long-press events without sacrificing text-selection in the WebView. Hopefully this helps.
#Override
protected void onCreate(Bundle savedInstanceState) {
WebView mWebView = (WebView) findViewById(R.id.myWebView);
GestureDetector mGestureDetector = new GestureDetector(this, new CustomGestureListener());
mWebView.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View view, MotionEvent arg1) {
//Suggestion #1 - this just lets the touch to be handled by the system but allows you to detect long presses
mGestureDetector.onTouchEvent(arg1);
return false;
//Suggestion #2 - this code will only let the touch be handled by the system if you don't detect a long press
return mGestureDetector.onTouchEvent(arg1);
}
});
}
private class CustomGestureListener extends SimpleOnGestureListener {
#Override
public void onLongPress(MotionEvent e) {
//do stuff
}
}

Categories

Resources