Showing Menu in one of the fragments of View Pager - android

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

Related

Why my MenuItem is not being hidden?

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);
}

How to NOT call onCreateOptionsMenu when calling FragmentManager.replace()

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.

Android - Correct use of invalidateOptionsMenu()

I have been searching a lot on invalidateOptionsMenu() and I know what it does. But I cannot think of any real life example where this method could be useful.
I mean, for instance, let's say we want to add a new MenuItem to our ActionBar, we can simply get the Menu from onCreateOptionsMenu(Menu menu) and use it in any button's action.
Now to my real question, is following the only way of using invalidateOptionsMenu()?
bool _OtherMenu;
protected override void OnCreate (Bundle bundle)
{
_OtherMenu = false;
base.OnCreate (bundle);
SetContentView (Resource.Layout.Main);
Button button = FindViewById<Button> (Resource.Id.myButton);
button.Click += delegate
{
if(_OtherMenu)
_OtherMenu = false;
else
_OtherMenu = true;
InvalidateOptionsMenu ();
};
}
public override bool OnCreateOptionsMenu (IMenu menu)
{
var inflater = this.SupportMenuInflater;
if(_OtherMenu)
inflater.Inflate (Resource.Menu.another_menu, menu);
else
inflater.Inflate (Resource.Menu.main_activity_menu, menu);
return base.OnCreateOptionsMenu (menu);
}
Click the button and a different menu appears. Click the button again and previous menu appears.
P.S. Sorry for the C# syntax.
invalidateOptionsMenu() is used to say Android, that contents of menu have changed, and menu should be redrawn. For example, you click a button which adds another menu item at runtime, or hides menu items group. In this case you should call invalidateOptionsMenu(), so that the system could redraw it on UI. This method is a signal for OS to call onPrepareOptionsMenu(), where you implement necessary menu manipulations.
Furthermore, OnCreateOptionsMenu() is called only once during activity (fragment) creation, thus runtime menu changes cannot be handled by this method.
All can be found in documentation:
After the system calls onCreateOptionsMenu(), it retains an instance
of the Menu you populate and will not call onCreateOptionsMenu() again
unless the menu is invalidated for some reason. However, you should
use onCreateOptionsMenu() only to create the initial menu state and
not to make changes during the activity lifecycle.
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.)
On Android 2.3.x and lower, the system calls onPrepareOptionsMenu()
each time the user opens the options menu (presses the Menu button).
On Android 3.0 and higher, the options menu is considered to always be
open when menu items are presented in the action bar. When an event
occurs and you want to perform a menu update, you must call
invalidateOptionsMenu() to request that the system call
onPrepareOptionsMenu().
use this to reload new menu during app lifecycle:
new:
getActivity().invalidateOptionsMenu();
old
ActivityCompat.invalidateOptionsMenu(getActivity());
You need to override method onPrepareOptionsMenu(), write your update code of action menu in same method and if you are using fragment then add setHasOptionsMenu(true); in onCreateView().
Hope it helps you
One use I've found is forcing an order of operations between onResume and onCreateOptionsMenu/onPrepareOptionsMenu. The natural order (as of platform 22 at least) seems to flip flop around, especially when re-orientating your device.
Call invalidateOptionsMenu() in onResume() and you'll guarantee that onPrepareOptionsMenu will be called after onResume (it may additionally be called before). For example, this will allow enabling a menu item based on data retrieved in onResume.
/**
* Set a hint for whether this fragment's menu should be visible. This
* is useful if you know that a fragment has been placed in your view
* hierarchy so that the user can not currently seen it, so any menu items
* it has should also not be shown.
*
* #param menuVisible The default is true, meaning the fragment's menu will
* be shown as usual. If false, the user will not see the menu.
*/
public void setMenuVisibility(boolean menuVisible) {
if (mMenuVisible != menuVisible) {
mMenuVisible = menuVisible;
if (mHasMenu && isAdded() && !isHidden()) {
mHost.onSupportInvalidateOptionsMenu();
}
}
}
XML menu sample:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_edit"
android:icon="#drawable/ic_edit"
android:title="Edit Task"
app:showAsAction="always" />
<item
android:id="#+id/action_delete"
android:icon="#drawable/ic_delete"
android:title="Delete Task"
app:showAsAction="always" />
<item
android:id="#+id/action_check"
android:icon="#drawable/ic_check"
android:title="Check Task"
app:showAsAction="always" />
<item
android:id="#+id/action_uncheck"
android:icon="#drawable/ic_undo"
android:title="Uncheck Task"
app:showAsAction="always" />
</menu>
Code inside a sample fragment:
private boolean isMenuItemChecked;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setMenuVisibility(false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.my_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
try {
menu.findItem(R.id.action_check).setVisible(!isMenuItemChecked);
menu.findItem(R.id.action_uncheck).setVisible(isMenuItemChecked);
}
catch(Exception e) {
Log.e(TAG, "onPrepareOptionsMenu error");
}
}
public void loadUi(boolean isMenuItemChecked) {
this.isMenuItemChecked = isMenuItemChecked;
setMenuVisibility(true);
}
Put the initial state of the menu in onCreateOptionsMenu(...).
Use the invalidateOptionsMenu() to force onCreateOptionsMenu(...) and onPrepareOptionsMenu(...).
In onPrepareOptionsMenu(...), call menu.clear() to remove all items from the menu.
Still in onPrepareOptionsMenu(...) place your dynamic menu changes after the clear.
Edit: Here is a better answer to the question.
A good use for invalidateOptionsMenu() is when we have a ListView and Delete All MenuItem so when the ListView is empty we should use invalidateOptionsMenu() to remove the Delete All MenuItem.
Here is a question related to this answer: Question.
It's old, but hope this helps some one out in the future.
One use I found on real life scenario:
Assume you've a list of items that are stored into database, and you've 2 activities:
DisplayActivity: which displayed these objects after getting them
from database.
EditActivity: used to edit an existing item & save that into database.
You decided to have a couple of options to go from DisplayActivity to EditActivity:
First: To add a brand-new item into database.
Second: To edit an existing item.
In order not to repeat yourself by duplicating code, you decided to use EditActivity for both purposes.
And so, you want to customize Options Menu according to each purpose. For this case you'd build a default options menu using onCreateOptionsMenu(), and leave it as-is when it's time to edit an existing item; and invalidateOptionsMenu() it when it's time to create new items; and in this case onPrepareOptionsMenu() is auto triggered for customizing your menu.
For instance the Options menu can have a delete option for editing an existing item, and this should be hidden when adding a new item.
From fragment call getActivity().invalidateOptionsMenu();.

How to set action bar and left drawer attributes for fragments according to their types

I have various types of fragment in my application and there are 3 icons on ActionBar (filter, refresh and sort) but I don't want to show all 3 icons in each of the fragments. I have to show only some of them according to the fragment.
Similar thing I want to do with left drawer. On some fragments I want to show left drawer whereas don't want to display left drawer on others.
I have a Activity class in my application on which I am attaching these fragments and currently I am handling these two things in this class and code has become mess with if-else conditions.
So right now I am checking fragment name and then setting action bar icons and left drawer attributes according to it.
Please tell me a better way to do it( preferably to handle this in Fragment itself)
Thanks
Fragments have access to their activity through getActivity() function which will return non-null activity after onAttach() is called (and before onDetach()). Once the fragment has the activity it can tell it to do whatever you were doing right in the activity manually with checks, including changing the action bar buttons.
In order to show the options depending on the fragment, you can simply do the following:
Add setHasOptionsMenu(true) to the onCreate() method of the fragment and tell the Activity to redraw its options menu.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
getActivity().invalidateOptionsMenu();
}
Next override the onCreateOptionsMenu() method to inflate the options that you want for your fragment.
// No support library - support library api slightly different
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Add Fragment menu elements to Activity menu elements
inflater.inflate(R.menu.myfragmentmenu, menu);
super.onCreateOptionsMenu(menu,inflater);
}
Finally make sure to capture all option items in the onOptionsItemSelected() method of your activity.
(Important note: make sure to replace fragments instead of adding them. Otherwise onCreateOptionsMenu() will be called for each fragment.)
In order to disable and enable the drawer, you can add the following method to your Activity and call it from your fragment:
public void toggleDrawer(boolean enabled) {
if (enabled) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerToggle.setDrawerIndicatorEnabled(true);
} else {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
mDrawerToggle.setDrawerIndicatorEnabled(false);
}
}
Create a new project from a sample project called ActionBarCombat and also download this sample application here http://www.learn2crack.com/2014/06/android-sliding-navigation-drawer-example.html
I once combined the two to come up with an application has action bar attributes as well as left drawer
To structure your code a bit why don't you create some methods in your activity like displayRefreshIcon(boolean visible) in which you handle the visibly of these items.
From your fragment you can call these methods (like frangulyan suggests) through the getActivity() function.
If (getActivity() != null && getActivity() instanceof MyActivity) {
((MyActivity)getActivity()).displayRefreshIcon(true);
}
In main thread or usual it is somehow impossible to do make changes in the activity itself, because fragments are separated module who are attached with activities but not the part of them.
But there is a shortcut that is to send message (handler) to activity to update the show the respective actionbar components
(most probably if you are using this fragment only for specific activity).
There you should make a base fragment and each fragment should extend baseFragment and at onResume method you have to check instance of Fragment then according to them you can update actionBar View.
Using any type of fragment, you should just have access to the methods (you have to override them): onCreateOptionsMenu, onPrepareOptionsMenu and onOptionsItemSelected. These methods should provide you with plenty of handles to create a menu per fragment. You could create a menu layout file per fragment and handle them in the method designed to do so. The methods:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.overviewmenu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}

Refresh actionbar item icon

This works just fine but If I'm on a different activity and I use the back button, it won't update the action bar because the activity is already created and it won't update the action bar. Already tried to use supportInvalidateOptionsMenu() on the on_create method but it didn't work.
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
Cursor cursor = messages.getMessages();
if(cursor.getCount()>0){
inflater.inflate(R.menu.actionbar1, menu);
}else{
inflater.inflate(R.menu.actionbar2, menu);
}
return super.onCreateOptionsMenu(menu);
}
As the documentation for onCreateOptionsMenu(Menu) states:
This is only called once, the first time the options menu is
displayed. To update the menu every time it is displayed, see
onPrepareOptionsMenu(Menu).
So going back to an already created Activity does not trigger onCreateOptionsMenu(Menu) again.
What I suggest you to do is create just one menu containing all the menu items and selectively activate/deactivate them in onPrepareOptionsMenu(Menu) based on one or more flags. Then put invalidateOptionsMenu() in onResume() which is called every time the Activity is shown.
Hope it helps
Try calling invalidateOptionsMenu whenever you need to change the icon.
It will destroy your menus and re-inflate them by calling onPrepareOptionsMenu.

Categories

Resources