I have an Activity that has 2 fragments. Both are ListFragments and both contribute MenuItems to the Menu. I have one MenuItem that I've set the attribute android:showAsAction to have it show as a button on the ActionBar. Which works fine.
Now the MenuItem is state dependent. It's a Pause/Resume menu option for pausing and resuming a queue. My problem is I can't figure out how to set it's initial statue when the Fragment is created.
It's state is dependent on the whether the queue is paused or not. So I have an AsyncTask that gets the queue and sets a boolean (paused) based on the state of the queue. I'm calling onPrepareOptionsMenu to set the text for the Pause menu item based on the last known state of the queue and this works great if I leave the MenuItem in the actual menu. You tap the menu icon and onPrepareOptionsMenu is fired and the menu is updated before it's displayed.
The problem is, if I put that same MenuItem on the ActionBar (showAsAction), how can I force it to update without having to call onPrepareOptionsMenu? I need to be able to do this because on first launch of the app, I send a request to get the queue, but the task returns after the ActionBar is setup and displayed. I've created a handler in my fragment that gets called every time I get a queue update, but from there, how can I update the text for my MenuItem on the ActionBar? I can't seem to find a way to get the currently set Menu to manipulate it except for in onPrepareOptionMenu.
Rob W.
Option #1: Try invalidateOptionsMenu(). I don't know if this will force an immediate redraw of the action bar or not.
Option #2: See if getActionView() returns anything for the affected MenuItem. It is possible that showAsAction simply automatically creates action views for you. If so, you can presumably enable/disable that View.
I can't seem to find a way to get the currently set Menu to manipulate it except for in onPrepareOptionMenu.
You can hang onto the Menu object you were handed in onCreateOptionsMenu(). Quoting the docs:
You can safely hold on to menu (and any items created from it), making modifications to it as desired, until the next time onCreateOptionsMenu() is called.
in my case: invalidateOptionsMenu just re-setted the text to the original one,
but directly accessing the menu item and re-writing the desire text worked without problems:
if (mnuTopMenuActionBar_ != null) {
MenuItem mnuPageIndex = mnuTopMenuActionBar_
.findItem(R.id.menu_magazin_pageOfPage_text);
if (mnuPageIndex != null) {
if (getScreenOrientation() == 1) {
mnuPageIndex.setTitle((i + 1) + " von " + pages);
}
else {
mnuPageIndex.setTitle(
(i + 1) + " + " + (i + 2) + " " + " von " + pages);
}
// invalidateOptionsMenu();
}
}
due to the comment below, I was able to access the menu item via the following code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.magazine_swipe_activity, menu);
mnuTopMenuActionBar_ = menu;
return true;
}
To refresh menu from Fragment simply call:
getActivity().invalidateOptionsMenu();
I have used this code:
public boolean onPrepareOptionsMenu (Menu menu) {
MenuInflater inflater = getMenuInflater();
TextView title = (TextView) findViewById(R.id.title);
menu.getItem(0).setTitle(
getString(R.string.payFor) + " " + title.getText().toString());
menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
return true;
}
And worked like a charm to me you can find OnPrepareOptionsMenu here
First please follow the two lines of codes to update the action bar items
before that you should set a condition in oncreateOptionMenu().
For example:
Boolean mISQuizItemSelected = false;
/**
* Called to inflate the action bar menus
*
* #param menu
* the menu
*
* #return true, if successful
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
inflater.inflate(R.menu.menu_demo, menu);
//condition to hide the menus
if (mISQuizItemSelected) {
for (int i = 0; i < menu.size(); i++) {
menu.getItem(i).setVisible(false);
}
}
return super.onCreateOptionsMenu(menu);
}
/**
* Called when the item on the action bar being selected.
*
* #param item
* menuitem being selected
*
* #return true if the menuitem id being selected is matched
* false if none of the menuitems id are matched
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getId() == R.id.action_quiz) {
//to navigate based on the usertype either learner or leo
mISQuizItemSelected = true;
ActionBar actionBar = getActionBar();
invalidateOptionMenu();
}
}
For clarity, I thought that a direct example of grabbing onto a resource can be shown from the following that I think contributes to the response for this question with a quick direct example.
private MenuItem menuItem_;
#Override
public boolean onCreateOptionsMenu(Menu menuF)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_layout, menuF);
menuItem_ = menuF.findItem(R.id.menu_item_identifier);
return true;
}
In this case you hold onto a MenuItem reference at the beginning and then change the state of it (for icon state changes for example) at a later given point in time.
Related
I have been struggling to implement switching visibility of Share option on Menu between fragments. I am using sliding tab layout and has a fragment in each of the 2 tabs. First tab (uses list view) and when an item is selected, I am setting a flag as true and calls invalidateOptionsMenu() and it works fine by showing a share option on the App bar menu, but I am not able to cancel it when I move to the other fragment which has mainly preferences. Code is similar to the below.
public void setSharedIntentText(String text) {
sharedText = text;
if (shareOptionVisibility == false) {
shareOptionVisibility = true;
invalidateOptionsMenu();
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
// Locate MenuItem with ShareActionProvider
MenuItem shareItem = menu.findItem(R.id.menu_share);
// Fetch and store ShareActionProvider
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareItem);
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_TEXT, sharedText);
mShareActionProvider.setShareIntent(sendIntent);
shareItem.setVisible(shareOptionVisibility);
When I switch between tabs, visibility should be set appropriately. I tried to set it onPause method of the first fragment, and then onResume method of second fragment, but control doesn't seem to go these methods when I look at the logcat. The code I have used to set visibility to false is as below in fragment2.
public void onResume() {
super.onResume();
Log.i(TAG, "On Resume ");
((MainActivity) getActivity()).shareOptionVisibility = false;
((MainActivity) getActivity()).invalidateOptionsMenu();
}
So would like to know where is the best place to put the code to control visibility when we switch between tabs. Here are the list of classes I use.
MainActivity, fragment1, fragment2, SlidingTabLayout, SlidingTabStrip and ViewPagerAdaptor. This code was implemented on top of the com.example.android.actionbarcompat.shareactionprovider example.
Thanks in advance
Issue now resolved by implementing the onCreateOptionsMenu method from the fragment rather than from the MainActivity.
Thanks
My menu has a item to Log in, but when you are logged in I want it to say Log out.
How?
If I'm going to change the item after its created, its probably through this method
#Override
public boolean onCreateOptionsMenu( Menu menu ) {
MenuInflater inflater = getMenuInflater();
inflater.inflate( R.menu.menu_main, menu );
return true;
}
Afaik the onCreateOptionsMenu() happens after the onCreate so putting any getItemId() for the menu there will give me a NullPointerException right away.
I want the app to find out if its supposed to use the string R.string.Logout if its logged in.
I dont even know what to search for for this issue. All I found was how to make a string implement names, like this answer https://stackoverflow.com/a/7646689/3064486
You should use onPrepareOptionsMenu(Menu menu) instead to update menu items
#Override
public boolean onPrepareOptionsMenu(Menu menu){
super.onPrepareOptionsMenu(menu);
MenuItem someMenuItem = menu.findItem(R.id.some_menu_item);
someMenuItem.setTitle("Log out");
return super.onPrepareOptionsMenu(menu);
}
To refresh Menu items call invalidateOptionsMenu();from Activity
From Android API guides: "If you want to modify the options menu based on events that occur during the activity lifecycle, you can do so in the onPrepareOptionsMenu() method. This method passes you the Menu object as it currently exists so you can modify it, such as add, remove, or disable items. (Fragments also provide an onPrepareOptionsMenu() callback.)"
After you inflate a menu, you can customize its items. To get each one, you must call findItem() with the item's id. In particular, you can use setTitle() to change the displayed string.
For example:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
if (mIsLoggedIn)
menu.findItem(R.id.action_login).setTitle("Log out");
return true;
}
where action_login is the id you set for this particular menu item in the menu's xml file.
private void updateUI() {
runOnUiThread(new Runnable() {
#Override
public void run() {
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
Menu menu = navigationView.getMenu();
MenuItem nav_signin = menu.findItem(R.id.nav_signin);
nav_signin.setTitle(MyApp.signedIn ? "Sign out" : "Sign in");
}
});
}
I have a item menu (sorting list) in my actionbar that I have to set its visibility to VISIBLE / GONE (depending on the list size -> empty or not).
So what I need is to check if listview is empty or not and set the visibility of that menu item accordingly, and I managed to came up with some code to do that (check listview size in onCreateOptionsMenu and set menu item visibility), but the problem is that the list can change its content both from same activity or from another, leaving me no option (IMO) than to check again listview size and set visiblity in onResume().
Here comes next problem: setting visibility of that item in onResume(), will throw a NPE, as I don't yet have that MenuItem initialized (onCreateOptionsMenu is called after onResume).
Any ideas on how to solve this situation would be appreciated.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getSupportMenuInflater().inflate(R.menu.main, menu);
/*
* initialize sortMenuItem so it can be used for turning visibility
* on/off in onResume()
*/
sortMenuItem = menu.findItem(R.id.menu_sort);
return true;
}
#Override
public void onResume() {
super.onResume();
boolean isListEmpty = mInterviewsList.isEmpty();
Log.d(LOG_TAG, "sortMenuItem is null? " + (sortMenuItem == null));
// sortMenuItem is indeed null
sortMenuItem.setVisible(isListEmpty);
sortMenuItem.setEnabled(!isListEmpty);
this.invalidateOptionsMenu();
}
You can add sortMenuItem dynamicaly in onCreateOptionsMenu depending on your listview size and in onResume call supportInvalidateOptionsMenu() if you use (google ActionBar compat lib) or similar method.
I have an options menu in an Activity with three MenuItems
create
select
delete
When there is no item currently selected I disable the MenuItem for delete.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
final MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.basic_menu, menu);
this.deleteCharMenu = menu.findItem(R.id.basic_menu_deletechar);
this.deleteCharMenu.setEnabled(this.current != null);
return true;
}
However onCreateOptionsMenu is not called every time the menu is opened (try and error got me this result).
So I stored the MenuItem in a class variable to be able to change its state whenever this.current changed its value.
Is there a more elegant method to ensure that the correct MenuItems are enabled and disabled? I am hoping for some kind of listener I can use?
overload the onPrepareMenu , it is called right before it's shown.
In Android, I create my menu item like this?
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, "Menu1");
menu.add(0, 1, 0, "Menu2");
return true;
}
How can I set all the menu item disabled programmatically (in another part of the code in my activity, not in onCreateOptionsMenu() method itself)?
You can use the groupId you set to disable/enable all the menu items at once, using menu.setGroupEnabled(). So for example, since you added the items to group 0, you'd do:
menu.setGroupEnabled(0, false);
Also, if you want to dynamically modify the menu, you should hook into onPrepareOptionsMenu(). onCreateOptionsMenu() is only called once per Activity, so it's good for setting up the initial menu structure, but onPrepareOptionsMenu() should be used to enable/disable menus as necessary later in the Activity.
add returns a MenuItem (which you can also retrieve from the Menu object), that you can store away into a variable.
MenuItem menu1;
public boolean onCreateOptionsMenu(Menu menu) {
menu1 = menu.add(0, 0, 0, "Menu1");
}
public void someOtherMethod() {
if(menu1 != null) {
// if it's null, options menu hasn't been created, so nevermind
menu1.setEnabled(false);
}
}
I prefer to hide them completely if they should not be used (instead of disabling them).
For that I do:
menu.clear();
and to recreate it:
invalidateOptionsMenu();
This also works for menu items added from fragments.
If still relevant:
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
for(int i=0; i<menu.size(); i++){
menu.getItem(i).setEnabled(isMenuEnabled);
}
}
and call invalidateOptionsMenu() then isMenuEnabled changed
If you have multiple occasions where you want to do something with all items of a menu (for example changing the 'checked' state) there is an elegant solution using Kotlin Extension Properties:
(Building on top of the answer of Valery)
In one place define the property 'items' of android.view.Menu:
import android.view.Menu
import android.view.MenuItem
val Menu.items: List<MenuItem>
get() {
val items = mutableListOf<MenuItem>()
for (i in 0 until this.size()) {
items.add(this.getItem(i))
}
return items
}
Now you can use it on any menu:
anyMenu.items.forEach { it.isEnabled = false }