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);
}
});
Related
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();
I have this recurring issue with the onCreateOptionsMenu method. I have it set up so it enables or disables options depending on the value of some SharedPreferences, but for some reason the first time you open the menu it doesn't work as it should, the options that should be disabled are enabled and the other way around. If I close it and reopen it, it works fine.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
menuConfig(menu);
return true;
}
#Override
public boolean onPrepareOptionsMenu (Menu menu) {
menuConfig(menu);
return true;
}
public void menuConfig(Menu menu){
menu.getItem(getResources().getInteger(R.integer.MENU_ABOUT)).setEnabled(true);
if (preferences.getBoolean(getString(R.string.PREFS_STARTED), false)){
menu.getItem(getResources().getInteger(R.integer.MENU_START)).setEnabled(false);
menu.getItem(getResources().getInteger(R.integer.MENU_STOP)).setEnabled(true);
}else{
menu.getItem(getResources().getInteger(R.integer.MENU_START)).setEnabled(true);
menu.getItem(getResources().getInteger(R.integer.MENU_STOP)).setEnabled(false);
}
if(!preferences.getBoolean(getString(R.string.PREFS_STARTED),false) && preferences.getBoolean(getString(R.string.PREFS_FILES_CREATED),false)){
menu.getItem(getResources().getInteger(R.integer.MENU_DELETE)).setEnabled(true);
menu.getItem(getResources().getInteger(R.integer.MENU_SET_ID)).setEnabled(true);
}
else{
menu.getItem(getResources().getInteger(R.integer.MENU_DELETE)).setEnabled(false);
menu.getItem(getResources().getInteger(R.integer.MENU_SET_ID)).setEnabled(false);
}
}
These two pics are taken subsequently with a few seconds between each menu key press.
The first one is wrong, it should look like the second one.
I fixed it by changing the default value returned by the queries to the SharedPreferences object but I have no idea of what is actually happening.
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()".
An Android device configuration change (for example "slide the hard keyboard back in") will always call PhoneWindow.onConfigurationChanged(), which in turn, will call reopenMenu(). This will cause the menu of the currently running activity to be reopened, in case it is showing.
I have a lock on my menu implemented in my onPrepareOptionsMenu() override. The user must enter a code each time they want to see the menu. I don't want the user to be asked to enter the code again, while the menu is still up just because of a configuration change. Thus, I would like to know, is there any way I can check if the menu of current foreground activity is already showing? Knowing this, I could bypass asking for the access code if the menu is already up.
My custom workaround implementation is to use my own flag menuShowing, which I set in onPrepareOptionsMenu and reset in onOptionsItemSelected and in onKeyDown if the back button is clicked.
EDIT: It appears a screen orientation configuration change does not trigger this behavior. A hard keyboard slide however, does.
Until someone comes up with a nicer 'one call' answer, here is the custom workaround implementation that I mention in the question, with help from Sam's tips, in case someone needs the same functionality:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (showingMenu) {
// The menu button was clicked or the hard keyboard was
// slid open/closed while the menu was already showing
return true;
}
// Otherwise, either the menu was clicked or openOptionsMenu() was called
if (codeEntered) {
// Code was entered and then openOptionsMenu() was called
showingMenu = true;
// Menu will now be shown
return true;
} else {
// The menu button was clicked, ask for code
askForCode();
// Don't show menu yet
return false;
}
}
#Override
public void onOptionsMenuClosed(Menu menu) {
showingMenu = false;
codeEntered = false;
}
private void askForCode() {
codeEntered = getUserInput();
if (codeEntered)
openOptionsMenu();
}
getUserInput() actually occurs with the help of an AlertDialog and an EditText with an attached TextWatcher but the implementation details exceed the scope of this question, unless someone is interested.
In my case it´s
#Override
public void onPanelClosed(int featureId, Menu menu) {
showingMenu = false;
super.onPanelClosed(featureId, menu);
}
Okay, so I have an option menu for my current app and it is the same with every class. okay, so I would like to know how to dim the options that are included in the menu when the selected class is already selected. For example, I have the Main Home on my option menu. When I am at the Main Home screen...it does appear on the option menu to click. How in the heck do you dim this? I tried looking on the android development page..but had no luck.. yet, I see it on other apps and it is driving me crazy! Surely, I am sure it is easy to mark the code out..but how can you do it! it is driving be bananas!
http://developer.android.com/guide/practices/ui_guidelines/menu_design.html#dim_hide_menu_items
You can override onPrepareOptionsMenu and disable the relevant menu item(s).
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
boolean ok = super.onPrepareOptionsMenu(menu);
if (ok) {
MenuItem item = menu.findItem(id_for_this_screen);
if (item != null) {
item.setEnabled(false);
}
}
return ok;
}