Android: menuItem.expandActionView() on API level < 14 - android

I am implementing a search interface on my application using the search widget. I do not plan to support any API level < 11 (Honeycomb). In the search activity, I'd like to override onKeyDown() to expand the search widget when user presses the search key, and minimize it when the query text is submitted.
This is easily accomplished by calling:
#Override
public boolean onSearchRequested() {
if (mSearchMenuItem != null) {
mSearchMenuItem.expandActionView();
}
return false;
}
and when the query is submitted:
searchView.setOnQueryTextListener(new OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
//Do nothing, results for the string supplied are already shown.
//Just collapse search widget
mSearchMenu.collapseActionView();
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
//do other stuff
return false;
});
The problem is that both collapse and expand were introduced in API level 14. As mentioned earlier I want to provide support as far back as API level 11, and I'm having trouble achieving the same functionality without calling the new API methods.
I tried:
#Override
public boolean onSearchRequested() {
searchView.setIconifiedByDefault(false);
//and also called
searchView.requestFocusFromTouch();
}
but that simply didn't do anything at all (by anything I mean the searchwidget remains collapsed if it already was.
Since I am keeping the reference to the menuItem, I also tried:
#Override
public boolean onSearchRequested() {
SearchActivity.this.onOptionsItemSelected(mSearchMenuItem);
}
but that didn't do anything at all either, last thing I tried was:
#Override
public boolean onSearchRequested() {
searchMenu.getActionView().performClick();
return false;
}
But that is no-go as well.
Any ideas on what I could do to provide the same functionality as menuItem.collapseActionView() and menuItem.expandActionView() without having to sacrifice compatibility?

This works on API level 10 for expanding ActionView e.g. SearchView
MenuItemCompat.expandActionView(mSearchMenuItem);

You can use MenuItemCompat static methods. Example:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_search, menu);
MenuItem menuItem = menu.findItem(R.id.action_search);
MenuItemCompat.expandActionView(menuItem);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
...
}
More info: http://developer.android.com/reference/android/support/v4/view/MenuItemCompat.html

You always have the option of differentiating your solution depending on the current running version:
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
// pre honeycomb
} else {
// honeycomb and post
}
I know this might not be exactly what you are looking for but it might get you some of the way .

Related

Custom searchview in actionbar

I have a searchview in my application. I need to search some information when user writes some criteria and after this, need show result in ListView.
How is it possible to know, if the user pressed the search button on the keyboard or not?
I read about OnQueryTextListener, but I still can't understand how to handle the press of a button from the android keyboard.
sv is the searchView
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
//here is what you want
return false;
}
#Override
public boolean onQueryTextChange(String s) {
// here you write what to do while typing
return false;
}
});

How can I tell when text is being typed into my Android SearchView on the ActionBar

I want to disable certain features of my app while the user is entering text for a search. The xml for the relevant item in my ActionBar is
<item android:id="#+id/actionbar_search"
android:orderInCategory="1"
android:showAsAction="always|withText|collapseActionView"
android:actionViewClass="android.widget.SearchView"
android:icon="#drawable/earth_2508858_search_en"
android:inputType="textPostalAddress" />
and in the corresponding code that I have at present to cater for the search is
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_menu, menu);
MenuItem DestinationTxt = menu.findItem(R.id.actionbar_search);
final SearchView mySearchView = (SearchView)DestinationTxt.getActionView();
mySearchView.setOnQueryTextListener(new OnQueryTextListener() {
#Override
public boolean onQueryTextChange(String newText) { return false; }
#Override
public boolean onQueryTextSubmit(String query) {
//Hide the Keyboard
imm.hideSoftInputFromWindow(mySearchView.getWindowToken(), 0);
// CODE TO DO THE SEARCH
return true;
}
});
}
I've browsed the methods on SearchView, but I didn't see anything that would tell me whether it's active or not. I'm also worried about putting in a boolean state variable to indicate when the text is being typed into the SearchView, in case some behaviour that I haven't catered for occurs (e.g. back button pressed, activity gets suspended), and somehow the state variable gets stale so that the disabled features stay disabled. So I'm looking for a robust way of doing this, all help appreciated :-).
Update. An answer below suggests using the interface OnFocusChangeListener which is implemented by the mySearchView object, and/or the mySearchView.isFocussed() method. Both sounded promising, however I've now tested and neither seem to work. Perhaps their failure has got something to do with the fact that this SearchView is in the ActionBar? In any case, I'm still after a robust solution.
It's right there.
mySearchView.setOnQueryTextListener(new OnQueryTextListener() {
#Override
public boolean onQueryTextChange(String newText) { return false; }
That's where you'll get updates to text changes in the SearchView.
The return value should be as such (documentation):
Returns
false if the SearchView should perform the default action of showing any suggestions if available, true if the action was handled by the listener.
If you want to know if the SearchView has been activated or deactivated, use View.setOnFocusChangeListener(View.OnFocusChangeListener);
public interface OnFocusChangeListener{
public void onFocusChange (View v, boolean hasFocus);
// The boolean will tell you if it's focused or not.
}
Since monitoring the focus didn't work, I looked at the SearchView documentation again. It's a bit convoluted, but it seems like the intended solution to this problem.
If your SearchView is inflated from a menu XML in onCreateOptionsMenu(), then you can add this line:
menu.findItem(/* your SearchView's ID here */).setOnActionExpandListener(
new OnActionExpandListener(){
#Override
public boolean onMenuItemActionCollapse (MenuItem item){
enableInteraction();
return true; // Allow the SearchView to collapse.
}
#Override
public boolean onMenuItemActionExpand(MenuItem item){
disableInteraction();
return true; // Allow the SearchView to expand.
}
}
);
Then enable and disable your Activity's views in enableInteraction() and disableInteraction(), respectively. You should retain the MenuItem in your Activity so you can query it in onResume() like so:
#Override
public void onResume(){
super.onResume();
searchViewMenuItem.isActionViewExpanded() ?
disableInteraction() : enableInteraction();
}
This part might not be needed. The SearchView might automatically get collapsed when the Activity is hidden and stay that way, so you can simply call enableInteraction() in onResume() so your user isn't locked out.
If you just need to reference the state of the SearchView, use
searchViewMenuItem.isActionViewExpanded();

Changing options menu/actionbar menu programatically for 3.0+

In short, here's my question:
Can option menus (shown in the actionbar) be modified programatically on android 3.0+?
I have a wizard-style activity in which I use a ViewFlipper to switch between views, or steps.
The steps are: 1 -> 2 -> 3. Only the second screen (2) has a menu item, while the others don't. I have tried hanging on to the Menu reference (source) and either removing/adding items or just hiding/showing them.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
this.mMenu = menu;
getMenuInflater().inflate(R.menu.my_menu, menu);
mMenu.getItem(0).setVisible(false);
return super.onCreateOptionsMenu(menu);
}
Switch to the second screen ->
public void showNext(View v) {
if (mVFlipper.getDisplayedChild() < (mVFlipper.getChildCount() - 1)) {
mVFlipper.showNext();
if (mVFlipper.getDisplayedChild() == 1) {
setTitle("Second screen");
mMenu.getItem(0).setVisible(true);
}
}
}
This works fine on 2.2, but fails miserably on 4.1. Starting off with a visible MenuItem and hiding it later works. Starting off with an invisible menu item and showing it later -
There is a bug in Android's MenuItem setVisible that causes problems when turning items back to visible.
In your onCreateOptionsMenu(), add a check to see if the displayed page needs the Menu, if it does, add the MenuItem. Then, call invalidateOptionsMenu() whenever the page changes. That will rebuild the Menu.
I was also struggling with this issue, then I applied a small hack:
menu1.setEnabled(false);
menu1.setTitle("");
Then where you want to visible it again:
menu1.setEnabled(true);
menu1.setTitle("Okay"); //or you can set text according to your given updated values.
Problem fixed by having the MenuItem be visible after onCreateOptionsMenu finishes and then hiding it from a callback called after onCreateOptionsMenu:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
this.mMenu = menu;
getMenuInflater().inflate(R.menu.my_menu, menu);
boolean dummyVal = super.onCreateOptionsMenu(menu);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
mMenu.getItem(0).setVisible(true);
} else {
mMenu.getItem(0).setVisible(false);
}
return dummyVal;
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
if (mMenu != null) {
mMenu.getItem(0).setVisible(false);
}
}
}
If anyone has this problem, I recommend trying toadzky's suggestion first: calling "invalidateOptionsMenu()".

How to recognize whether the Done button is clicked in ActionMode

I use ActionMode to select items in a grid. The problem is that I cannot recognize whether exactly the Done button is clicked. The only I can is to know that ActionMode is finished. But pressing Back finishes the ActionMode too.
The desired behavior is to accept selection on Done click, and exit ActionMode on Back press.
I tried to use ActionMode.setCustomView() but it doesn't affect the Done button. The Activity.onBackPressed() is not called when ActionMode is started.
The one solution I've found is to use ActionBarSherlock and get the Done button manually:
View closeButton = findViewById(R.id.abs__action_mode_close_button);
But it works on Android 2.x-3.x only, because on 4.x a native action bar is used.
Please don't do that as it's implementation specific and extremely non-standard.
You can use the onDestroyActionMode callback for when an action mode is dismissed.
Here is the solution:
ActionMode mMode = MyActivityClass.this.startActionMode(some implementation);
int doneButtonId = Resources.getSystem().getIdentifier("action_mode_close_button", "id", "android");
View doneButton = MyActivityClass.this.findViewById(doneButtonId);
doneButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// do whatever you want
// in android source code it's calling mMode.finish();
}
});
Here is my implementation, and it's a proper hack but it works and I can't really find an alternative to doing something specific when the ActionMode DONE is clicked. I find it really weird that you can't capture this event more elegantly.
Any suggestions to making this slightly less ugly would be greatly appreciated...
In my activity..
boolean mActionModeIsActive = false;
boolean mBackWasPressedInActionMode = false;
#Override
public boolean dispatchKeyEvent(KeyEvent event)
{
mBackWasPressedInActionMode = mActionModeIsActive && event.getKeyCode() == KeyEvent.KEYCODE_BACK;
return super.dispatchKeyEvent(event);
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu)
{
mActionModeIsActive = true;
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode)
{
mActionModeIsActive = false;
if (!mBackWasPressedInActionMode)
onActionModeDoneClick();
mBackWasPressedInActionMode = false;
}
public void onActionModeDoneClick();
{
// Do something here.
}
If you are using Fragments with your Activity then some of this code will probably need to be in the Fragment, and the other bits in the Activity.
#JakeWharton (and other ActionBarSherlock users) if you see this on your travels. I'd be interested to know if the above is compatible with ABS as I have yet to integrate ABS with my current project.

Initially Hidden MenuItem Not Shown When setVisible(true) is Called

I have a basic problem where an initially hidden MenuItem is unable to be toggled to visible. As a caveat, I am using ActionBarSherlock, but I wanted to see if anyone knew if this was a known issue of Android or I am doing something terrible before investigating whether this is an issue inside of ABS. Code as follows:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.menu_xml, menu);
mMenuItem = menu.findItem(R.id.menu_item);
mMenuItem.setVisible(false);
return true;
}
// Somewhere elsewhere
// MenuItem is never visible after this line is executed
mMenuItem.setVisible(true);
I have also tried to move the mMenuItem assignment and visibility into a call to onPrepareOptionsMenu but the same behavior is shown.
Thanks!
The problem is you are not telling Android that it needs to update the menu. This drove me nuts for the last hour until I figured out a solution. I don't think it's as apparent on pre-HC because menu items aren't always visible on the screen like they are in HC+.
On your activity, simply call:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
this.invalidateOptionsMenu();
}
That will trigger a call to the onCreateOptionsMenu() event again, so if you're setting the visibility in that function for initialization you'll need to take into account then if you want the option to show or not.
I had the same problem and I found out that setVisible(true) works when there is at least another MenuItem visible. I hope this can be helpful to someone.
I understand this is old question.
But I've solved it by placing inside onPrepareOptionMenu() {...}
private boolean mShowVisible=false;
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.findItem(R.id.menu_item).setVisible(mShowVisible);
return super.onPrepareOptionsMenu(menu);
}
whenever you want to set visible or not just call it as:
mShowVisible = true; // or false
invalidateOptionMenu();
I found that using a view's post(Runnable) method to setVisible does the trick, so something like...
view.post(new Runnable() {
#Override
public void run() {
menu.findItem(id).setVisible(true);
}
});

Categories

Resources