Working with OptionsMenu in nested fragment - android

I use a NavigationDrawer pattern that is implemented in my hostactivity MenuActivity. My navigation has 3 items: Item 1, Item 2, Item 3.
Each itemis bonded to a fragment.
When I click on Item 1, I displayed a fragment A that implements a ViewPager with several fragments (nested fragments).
In my nested fragments, I inflate a menu with the following method (It works fine !) :
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.my_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
But when I click on another element of my menu (Item 2 -> display Fragment B or Item 3->display Fragment C), my menu (which was inflated in my nested fragment) is always visible but I want it to disappear.
Would you have a solution to this problem? Thank you in advance.

Just save child fragment and then override setMenuVisability:
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
if (savedFragment!= null)
savedFragment.setMenuVisibility(menuVisible);
}
it works for me

When I encountered this problem, I solved it by setting setHasOptionMenu(true) for both the child fragment and the "root" fragment. If the "root" fragment or another child fragment doesn't use option items, it's fine anyway, since you only inflate a menu in the child fragment needing it.

I just came across the problem and solved it by the following:
#Override
public void onDestroyOptionsMenu() {
this.setMenuVisibility(false);
super.onDestroyOptionsMenu();
Log.e(TAG, "onDestroyOptionsMenu");
}
#Override
public void onDestroyView() {
onDestroyOptionsMenu();
super.onDestroyView();
}
I noticed that onDestroyOptionsMenu is not being called so what I only did is call it from the OnDestroyView method and I set the menu visibility to false.

A slightly different approach from SafiS answer:
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(...) {
View view = ...
setMenuVisibility(true);
return view;
}
#Override
public void onDestroyView() {
setMenuVisibility(false);
super.onDestroyView();
}

Add setRetainInstance(true) and setHasOptionMenu(true) in onCreate() in fragment.

Related

Remove optionMenu from Fragment Toolbar

I am having an optionMenu at my MainActivity inflated inside onCreateOptionsMenu of my MainActivity and there are some fragments which are inflated inside the MainActivity which have their own Toolbars. But the problem is that the OptionMenu is also visible on the Toolbars inside the fragments. I don't want the fragments to have the OptionMenu for Fragments toolbar
setHasOptionsMenu(true) in your fragment onCreate();
in onCreateOptionsMenu inflate your fragment menu and remove MainActivity by using menu.removeItem(R.id.menu_id_to_be_removed); in onPrepareOptionsMenu
For the fragment you don't want onCreateOptionsMenu include following code in those fragments
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(false);
}
You can remove/hide overflow icon from toolbar by following the below steps
In your fragment where you want to hide it.
#Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState
) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_create_group,container,false);
setHasOptionsMenu(true);
}
override "onPrepareOptionsMenu". Like below
#Override
public void onPrepareOptionsMenu(#NonNull Menu menu) {
menu.clear();
}

Working with OptionsMenu in nested fragment not updating

I displayed a fragment A that implements a ViewPager with several fragments (nested fragments).
In my nested fragments, I inflate a menu with the following method.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.my_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
This question was already asked here. And i tried all the answers its not working.
My issue is
Everything working fine.but when i open another fragment(it have not any option menu) and get back to previous view pager fragment while clicking menu item onOptionsItemSelected not firing. When i swipe fragment in viewpager and come back to the previous one, when i click menu item its firing.
Its because viewpager maintain 3 fragment alive at a time. so when you come back, it set menu visibility status true to last fragment. thats why your menu item click not firing.
Use the following in the fragment where you keeping a viewpager in your case fragment A.
private boolean isInitial=true;
#Override
public void onResume() {
super.onResume();
if (!isInitial) {
int pos = viewpager.getCurrentItem();
if (pageAdapter.getItem(pos).getUserVisibleHint() && pageAdapter.getItem(pos).isVisible()) {
pageAdapter.getItem(pos).setMenuVisibility(true);
}
} else {
isInitial = false;
}
}

Fragment's onCreateOptionsMenu method is never called

I have an application with two activities hosting fragments. My main activity hosts a single fragment, and that fragment is able to define and inflate a menu that goes in the toolbar, no problem.
In the second activity, though, which uses a FragmentStatePagerAdapter to allow horizontal scrolling between items, my fragment does not seem able to define the menu in the toolbar.
Checks:
My whole app is set to use a theme (android:theme="#style/AppTheme") based on Theme.AppCompat.Light.DarkActionBar.
My fragment extends android.support.v4.app.Fragment
setHasOptionsMenu(true); is called from the fragment's onCreate() method
the hosting activity extends AppCompatActivity and does not implement a toolbar menu itself
my fragment overrides void onCreateOptionsMenu(Menu, MenuInflater), but this method seems to never be called
You can have a look at the commit that is supposed to add that menu on GitHub. (Or even look at any part of the code that might be a cause of error.)
Here are the big lines:
CrimeFragment.java:
public class CrimeFragment extends Fragment {
// ...
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
UUID id = (UUID) getArguments().getSerializable(ARG_CRIME_ID);
Log.d(TAG, String.format("Crime id in intent's extra: %s", id.toString()));
mCrime = CrimeLab.get(getActivity()).getCrime(id);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.d(TAG, "onCreateOptionsMenu()"); // <= Never shows in the Android Monitor
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_crime, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_delete_crime:
CrimeLab.get(getActivity()).deleteCrime(mCrime);
getActivity().finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
// ...
}
Is there something I'm doing wrong here?
Alright, it took me the time, but I finally found what was wrong with my code. This was a bit tricky.
In an earlier change, I overrode FragmentStatePagerAdapter#setPrimaryItem() in the hosting activity, in order to be informed every time the user switches between pages.
Unfortunately, in that override, I forgot to call super, and that's what was confusing the application, apparently.
I just had to add that call to super, and my menu item suddenly started to show up.
public class CrimePagerActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime_pager);
// ...
FragmentManager fragmentManager = getSupportFragmentManager();
mViewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
// ...
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object); // <= This line was missing
Crime crime = mCrimes.get(position);
mChangedCrimeIds.add(crime.getId());
}
});
mViewPager.setCurrentItem(CrimeLab.get(this).getPosition(crimeId));
}
// ...
}

OptionsMenu of Fragments in Viewpager showing each other's Buttons

I've got three fragments in a viewpager.
Two of these fragments have their own version of the onCreateOptionsMenu method:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// Set up 1 action button
inflater.inflate(R.menu.home_snapshot_add, menu);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// Set up 2 action buttons
inflater.inflate(R.menu.home_snapshot_send, menu);
}
The home activity has a basic onCreateOptionsMenu method:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return false;
}
In the onCreate method, each fragment calls the method:
setHasOptionsMenu(true);
Each of the menu items have the tag:
android:showAsAction="always"
Seems like as I open the Activity, all three buttons appear.
However, when I scroll through them, the wrong ones magically disappear.
It feels like the activity is calling every Fragment's options menu on Activity creation and then changes the menu appropriately when I swipe left and right.
I've checked the menus but not sure what's wrong.
Anything you reckon I need to check? I'm a little out of ideas.
Thanks!
In your ViewPager's OnPageChangeListener and after setting the adapter to the ViewPager, have this:
#Override
public void onPageSelected(int position){
invalidateFragmentMenus(position);
}
private void invalidateFragmentMenus(int position){
for(int i = 0; i < mViewPagerFragentAdapter.getCount(); i++){
mViewPagerAdapter.getItem(i).setHasOptionsMenu(i == position);
}
invalidateOptionsMenu(); //or respectively its support method.
}
After setting your fragment adapter call the same method with following argument:
invalidateFragmentMenus(mViewPager.getCurrentItem());
The above statements will prevent all other fragments not to receive call on onCreateOptionsMenu() method when invalidateOptionsMenu() is called, only the currently visible fragment will receive and be able to populate the options menu.
I've used this and it has worked for me:
//In your Fragment
#Override
public void onResume() {
super.onResume();
setHasOptionsMenu(isVisible());
}

FragmentStatePageAdapter duplicates ActionBar menu items

I have a problem with FragmentStatePageAdapter (that I use as adapter for a ViewPager) and the menu items from the action bar.
When I launch the application, everything is fine. If I move the task to background (for example, pressing HOME button) and I start doing stuff until the activity is ended, then when I go back to my application (through the launcher or a notification I create) everything is fine except there are duplicated menu items in the action bar.
An important detail is that the only duplicated items are those that are created in the onCreateOptionsMenu() of each fragment I use in the ViewPager.
If I replaceFragmentStatePageAdapter with FragmentPageAdapter the items are not duplicated anymore, but the fragments are not shown in the ViewPager (getItem() function from the adapter is never called so it does not return any fragment).
Any ideas? A way to avoid FragmentStatePageAdapter to duplicate menu items? Maybe use FragmentPageAdapter but with a modification to show the fragments? A modification in my fragments?
Here are some code snippets from my application...
How menu items are created inside the fragments:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
/* Create play button */
final MenuItem mPlay = menu.add(R.string.play_all);
mPlay.setIcon(R.drawable.ic_play_all);
mPlay.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
mPlay.setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
final List<Song> songs = getSongs();
if (songs.size() == 0) {
/* Show message */
Toast.makeText(mContext, R.string.no_song_list, Toast.LENGTH_LONG).show();
} else {
/* Play song list */
try { PlayManager.getService().playList(songs); } catch (Exception e) {}
}
return false;
}
});
/* Create menu */
super.onCreateOptionsMenu(menu, inflater);
}
How fragments are instantiated in the ViewPager adapter
#Override
public Fragment getItem(int position) {
final Class<?> cls = mTabs.get(position);
/* No tab */
if (cls == null)
return null;
/* Instantiate fragment */
final Fragment fragment = Fragment.instantiate(mContext, cls.getName(), null);
/* Add to list */
mFragments.put(position, fragment);
/* Return fragment */
return fragment;
}
Thanks!
PS: I tried to change the launchMode of the activity to "singleTop" and I also tried to return in getItem() the previosly created fragment (but that's useless as getItem() is never called when I return to the application, as I said before).
I found a solution to my problem a few days after posting my problem. I'm sorry for putting it here so late.
The following code fixed my problem:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.remove("android:support:fragments");
}
As simple as writing that piece of code in the activity where I instantiate and use the fragments.
I hope this helps :)
Before inflating the options menu in your Fragment inside the ViewPager, check whether the Fragment instance is visible to prevent duplicated menu items:
// This should be in your Fragment implementation
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
if(isVisible())
{
inflater.inflate(R.menu.menu_fragment, menu);
}
super.onCreateOptionsMenu(menu, inflater);
}
I assume the problem is that the FragmentStatePagerAdapter creates a new Fragment each time you swipe. As a result, onCreateOptionsMenu() is called for each Fragment that is created.
There are, I think, two solutions:
Take the action bar manipulation out of the Fragments. Instead of setting an onclick for the menu item inside of the Fragment, you send a message to the current Fragment from the Activity.
Use Menu.findItem() to see if another Fragment has already added the MenuItem you want, and if so attach the current Fragment to it (in onPrepareOptionsMenu()).
I found some solution try it may be work
In your duplicate menu fragment
Add menu.clear() before inflate menu file in onCreateOptionsMenu(Menu menu, MenuInflater inflater)
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.main,menu);
}

Categories

Resources