I have a Toolbar being used as an ActionBar with two items. I only want to ever display one at a time as they kind of replace each other. The problem is that when i replace a Fragment, it call onCreateOptionsMenu and will inflate the menu again, meaning that the same action button will be shown, even if the other one was previously in the ActionBar. I have to need to change anything in the ActionBar from my Fragments or when a new Fragment is displayed(with FragmentManager.FragmentTransaction.replace()). So my question is how do I not call onCreateOptionsMenu when a new fragment is displayed?
I can't use a boolean because I will still need it to reinflate on orientation change. And any advice on how to handle orentation change for my situation?
I can post code, but it seems more conceptual and I'm not sure that it would help.
I solved the problem by instead of not calling onCreateOptionsMenu, I added the items to my menu manually.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean refreshVisible;
if (refreshItem != null && refreshItem.isVisible()){//is being displayed prior to inflation
refreshVisible = true;
}else if (refreshItem == null){//it's null so the menu has never been created
refreshVisible = true;
}else {//it's not null and invisibe, other icon was being displayed
refreshVisible = false;
}
menu.clear();//clear menu so there are no duplicate or overlapping icons
getMenuInflater().inflate(R.menu.main, menu);//inflate menu
refreshItem = menu.findItem(R.id.refresh);
useDataItem = menu.findItem(R.id.use_data);
refreshItem.setVisible(refreshVisible);//if menu is being created for first time or item was previously visible, then display this item
useDataItem.setVisible(!refreshVisible);//display this item if not displaying other
return true;
}
I would fiddle with the onPrepareOptionsMenu hook. If you can detect that your menu should not be shown you should jest return false from there. Per documentation:
Prepare the Screen's standard options menu to be displayed. This is called right before the menu is shown, every time it is shown. You can use this method to efficiently enable/disable items or otherwise dynamically modify the contents.
and
You must return true for the menu to be displayed; if you return false it will not be shown.
You can call setHasOptionsMenu(false); inside your fragment.
This will prevent onCreateOptionsMenu() from being called when that fragment added.
Related
I am trying to hide a MenuItem of my menu but without success.
This is the code that I have right now:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onPrepareOptionsMenu(Menu menu){
MenuItem item = menu.findItem(R.id.lastOption);
item.setVisible(false);
invalidateOptionsMenu();
return true;
}
but it still shows that option when I run the application.
Trying to find why this behaviour happened, I tried to set some breakpoints to my code and found that menu variable has a variable called mVisibleItems. In that variable I can see that the item that I tried to hide does not appear. It appears on the application, though.
So, I cannot understand why if it does not appear on the menu visible variables, it still is shown on the application.
Am I missing something?
Thanks in advance!
invalidateOptionsMenu();, calls onCreateOptionsMenu again. From the documentation
Declare that the options menu has changed, so should be recreated. The
onCreateOptionsMenu(Menu) method will be called the next time it needs
to be displayed.
so, after setting your item to false, you are inflating the layout of your menu, again
I suppose that this is not the better way to do this but I could not do it using onPrepareOptionsMenu.
As I need two types of menu depending of the user that had logged in (admin or user) I finally do this creating two types of menu for my application. One with some options and one without the options that I do not need for a normal user. Then, on onCreateOptionsMenu I inflate the menu that I need depending of the user that has logged in.
This is the code:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
if("admin".equals(typeUser)){
getMenuInflater().inflate(R.menu.activity_main_admin, menu);
}else{
getMenuInflater().inflate(R.menu.activity_main_user, menu);
}
return true;
}
where typeUser is a String that I send from the Login Activity in which I set a bundle depending of the user that has logged in.
I also have created two activity_main layouts changing the menu option of the NavigationView on the XML:
app:menu="#menu/activity_main_admin" or app:menu="#menu/activity_main_user", depending on the layout.
Finally, I also have created a condition to set the layout on the onCreate method of MainActivity depending of the user that has logged in. This is the code to do this:
if("admin".equals(typeUser)){
setContentView(R.layout.admin);
}else{
setContentView(R.layout.user);
}
I am having Viewpager with 3 fragments. I want to show menu in only one of the fragments.
1st, I don't know why toolbar.inflateMenu doesn't work.
2nd, the menu works, if I have onPrepareOptionsMenu method and do
getMenuInflater().inflate(R.menu.add_user, menu); but the menu is displayed in all the fragments.
So, according to other questions in stack overflow, I implemented the below code, but it doesn't show the menu, it enters the method but menu is not shown.
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
//getMenuInflater().inflate(R.menu.add_user, menu);
info("Menu=>${tabs_viewpager.currentItem}")
val menuItem = menu?.findItem(R.id.addUserMenu)
menuItem?.setVisible(tabs_viewpager.currentItem == 1)
return true
}
The control comes to this method and shows currentItem. But it doesn't display the menu. Menu is there with id. Can someone direct me what can I correct to get this work?
try calling setHasOptionsMenu(true); in oncreate() of the fragments where you want the menu to show (you can set it to false in the fragments where you do not want the menu to show).
also include:
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
// your code
}
in the fragments where you want to set/change the menu. this is called everytime before the menu is shown.
you can also call invalidateOptionsMenu() or supportInvalidateOptionsMenu() (if you're using the support library) to force onPrepareOptionsMenu(menu) to be called.
you may want to check out this menus tutorial
good luck
clive
I get the menu item and then i try to set the visibility but the menu item is always shown. Can anyone see where I am making a mistake?
The menu item is not null and thus is allocated so thats not it.
MenuItem done = menu.findItem(R.id.action_done);
//animate the list view
if (isListEditing) {
done.setVisible(true);
menuItem.setTitle(this.getString(R.string.EditKey));
isListEditing = false;
adapter.endEdit();
} else {
done.setVisible(false);
menuItem.setTitle(this.getString(R.string.DoneKey));
isListEditing = true;
adapter.makeEditable();
}
this.invalidateOptionsMenu();
I get the menu reference here:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_test_results, menu);
this.menu = menu;
return true;
}
Update:
I was under the impression that you had to invalidate the options menu after you made an edit. But that is what was cause the edits to not go through.
According to the docs, what invalidateOptionsMenu() does is:
Declare that the options menu has changed, so should be recreated. The onCreateOptionsMenu(Menu) method will be called the next time it needs to be displayed.
That means onCreateOptionsMenu will get called again, inflating your original menu layout, and thus discarding your previous changes to the menu items visibility.
The recommended approach to modify the menu content dynamically is to use onPrepareOptionsMenu. So whenever you need to update menu items, you can call invalidateOptionsMenu(), and then inside onPrepareOptionsMenu, you set the menu items visibility.
There is no need for
this.invalidateOptionsMenu();
Take that off and it should work fine.
I would like to be able to append action bar items from my fragments.
For example in Landscape mode I have a list of items, and if clicked a page of information about that item appears.
The list can be changed by clicking the dropdown in the action bar to select a category of list.
Once a list item is clicked the details fragment is populated. I then want 3 tabs to be appended into the action bar so that the user can select which page of details is shown for that item, namely: "Details (default)";"Map"; and "Features".
In my fragment I can set setHasOptionsMenu(true) and then add the new tabs using the onCreateOptionsMenu call. This however deletes my dropdown which i still want displayed.
How does one simply append ActionBar Items..?
Thanks
I just call the fragment's onCreateOptionsMenu from my activity's onCreateOptionsMenu. You can add an if statement to decide to call the fragment's version or default call the fragment's onCreateOptionsMenu and put the if statement there to decide what to add. then, whenever it needs to change, just call invalidateOptionsMenu.
You will probably have to remove the setHasOptionsMenu call.
Activity:
public boolean onCreateOptionsMenu(Menu m)
{
// insert activity options
if (needFragmentOptions) {
fragment.onCreateOptionsMenu(m);
}
return true;
}
Fragment:
public boolean onCreateOptionsMenu(Menu m)
{
// insert fragment options
return true;
}
Do you know how to rename existing menu ?
I can rename when press menu item. But I don't know how to access to menu item when press the button.
Please advice.
It would be good if you can clarify the question a little, but each time the user presses the Menu on their Android device while inside one of your activities, the onPrepareOptionsMenu method is called. The first time the menu is shown (i.e. only once), the onCreateOptionsMenu method is called.
Basically, the onPrepareOptionsMenu method is where you should make any changes such as enabling/disabling certain menu items, or changing the menu item text depending on the circumstances.
As an example:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Check current message count
boolean haveMessages = mMessageCount != 0;
// Set 'delete' menu item state depending on count
MenuItem deleteItem = menu.findItem(R.id.menu_delete);
deleteItem.setTitle(haveMessages ? R.string.delete : R.string.no_messages);
deleteItem.setEnabled(haveMessages);
return super.onPrepareOptionsMenu(menu);
}
Use MenuItem.setTitle(). If this isn't what you needed, you have to be more specific.
The onPrepareOptionsMenu is the proper place to make changes to menuitems.