I am creating android application and I'm trying to respect as much as possible the latest Android usability standards. In particular, I am preparing the user interface using the navigation drawer, and I'm trying to ensure compatibility with 2.1+ Android versions. To appreciate the problem, the project consists of:
A main activity;
A navigation drawer;
Four fragments (with their associated layouts).
The problem I'm experiencing occurs when opening the navigation drawer: although each Fragment has its specific menu, when I open the navigation drawer it is added to the nav drawer menu. I tried in several ways (invalidateOptionMenu(), menu.clear(), manipulating functions isDrawerOpen() and isDrawerClose() and more), but I cannot remove the Fragment's menu when opening the navigationdrawer.
These are some snippets of my code, much of it generated by Android Studio, the IDE I'm using:
In main activity:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.global, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
where "global" is a simple menu with a classical "ic_action_overflow".
And in my fragments I've:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment1, menu);
}
(It's the same of the other Fragments).
Someone can give me some advice on how to act?
I faced the same problem using the boilerplate code generated by Android Studio and got it working by modifying the menu in NavigationDrawerFragment.onPrepareOptionsMenu() (in my case, I wanted to clear the menu altogether):
#Override
public void onPrepareOptionsMenu(Menu menu) {
if (mDrawerLayout != null && isDrawerOpen()) {
menu.clear();
}
}
This is roughly how the options menu is recreated:
NavigationDrawerFragment, which is generated by the IDE, calls supportInvalidateOptionsMenu() when the drawer is opened or closed.
onCreateOptionsMenu gets called: The hosting activity and each of the added fragments gets a chance to contribute menu items.
onPrepareOptionsMenu gets called: Again, the hosting activity and each of the added fragments get a chance to modify the menu.
The fragments are iterated in the order they were added. There is no way to stop the chain of calls midway in steps 2. and 3.
So the idea is to let NavigationDrawerFragment do last-minute changes to the menu in its onPrepareOptionsMenu and no other fragments.
If you need to let other fragments do something in onPrepareOptionsMenu, then you may have to setup those other fragments so they can determine if the drawer is open or not and change their behavior accordingly. This may mean perhaps adding a isDrawerOpen method to the hosting activity or passing in the drawer identifiers to the fragment like it's done in NavigationDrawerFragment.setup().
In your fragment onCreate, add this :
setHasOptionsMenu (true);
And then hide through onPrepareOptionsMenu. e.g.
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.action_settings).setVisible(false);
}
If you've implemented the navigation drawer the way Android Studio sets it up for you in its example code with a NavigationDrawerFragment, you should have two xml to start with main.xml (activity wide actionbar menu items) and global.xml (global items). I then added a fragment specific menu which adds items to the "activity menu items" as long as the drawer is closed...
Activity:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this activity
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.main, menu);
this.menu = menu;
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
NavigationDrawerFragment
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// If the drawer is open, show the global app actions in the action bar.
// See also showGlobalContextActionBar, which controls the top-left area
// of the action bar.
if (mDrawerLayout != null && isDrawerOpen()) {
inflater.inflate(R.menu.global, menu);
showGlobalContextActionBar();
}
super.onCreateOptionsMenu(menu, inflater);
}
and in your fragments add as you've described above
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Add fragment specific action bar items to activity action bar items.
// Activity wide items are in main.xml
// Visible action bar items if navigation drawer is visible/open
// are in global.xml
super.onCreateOptionsMenu(menu, inflater);
if (!mNavigationDrawerFragment.isDrawerOpen()) {
inflater.inflate(R.menu.fragment_menu, menu);
}
}
Check out this answer here: https://stackoverflow.com/a/18135409/2558344. Its basically using a boolean to clear items in the navigation drawer and vice versa. But alternatively, you could declare Menu menu as a private variable in your class and use it as: onCreateOptionsMenu(menu, MenuInflater inflater).
Then check in your fragments onStop(), onPause() if it's displaying items or not, if yes then clear them, like:
if (menu != null)
menu.clear();
Related
I have an activity in an android app with fragments displayed using a pager.
One of the three fragments shows a menu item (always displayed as action) and an overflow menu, the two others fragments show in the app bar only the first menu item (but not the overflow menu).
My problem is that when I switch from one tab to another, the menu is not updating smoothly.
Is it possible to add animations to menu inflation ?
Has anyone ever encountered such an issue and how did you handle it ?
Here is the app bar :
And here is how I inflate the menu inside the fragment, of course, the other fragment is inflating another XML file.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.home_menu, menu);
}
Please feel free to ask for more details ;-)
Thanks for helping !
In you fragment please write this line in your oncreateview mehod:
setHasOptionsMenu(true);
and implement this mehod:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_referesh, menu);
super.onCreateOptionsMenu(menu,inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.refresh:
pageNumber=1;
getWebServiceData1();
return false;
}
return super.onOptionsItemSelected(item);
}
I tried so many answers provided by various posts here but nothing worked for me.
Problem- I have navigation drawer that has 6 fragments but single activity. Everything worked fine till I changed 1st ranked fragment in drawer. I wanted Swipe tabs inside first fragment. So I used FragmentStatePagerAdapter.
Each fragment has its own menu along with MainActivity Menu.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Notify the system to allow an options menu for this fragment.
setHasOptionsMenu(true);
}
And inflated like this:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.story, menu);
}
Everything works fine. But When I visit other fragments in navigation drawer then it shows duplicate menu in toolbar. It creates more duplicates if there is space left in toolbar when I visit other fragments.
Try 1 : To solve this problem I initially used:
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.clear();
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.story, menu);
}
With this I don't get duplicate menu but now I don't see MainActivity menus.
Try 2:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
getActivity().invalidateOptionsMenu();
inflater.inflate(R.menu.story, menu);
}
With this I get both Fragment and Activity menu but Duplicates are there.
This should be easy to solve but I am not picking up a way to deal with this. Maybe I didn't understand the life cycle well?
My other approach- Implementing all menus in Fragments will do the trick but this should be our last option.
Solution to this - To maintain both Menu all I have to do is this (Very easy solution):
menu.clear();
inflater.inflate(R.menu.story, menu);
getActivity().getMenuInflater().inflate(R.menu.main, menu);
Problem 2 OnOptionsItemSelected method from 1st fragment is getting called in other fragments.
private void hideAllMenuItems() {
if (actionBarMenu != null) {
actionBarMenu.findItem(R.id.action_item1).setVisible(false);
actionBarMenu.findItem(R.id.action_item2).setVisible(false);
}
}
private void showMenuIcon() {
if (actionBarMenu != null) {
hideAllMenuItems();
if (currentFragment instanceof Fragment1)
actionBarMenu.findItem(R.id.action_item1).setVisible(true);
else if (currentFragment instanceof Fragment2)
actionBarMenu.findItem(R.id.action_item2).setVisible(true);
}
}
call shoeMenuIcon() each time new fragment load..
Hope you are looking for this
I have implemented ActionBar Navigation using Fragment. In my App i have one Activity and rest is in Fragments. In my MainActivity i am implementing menu like this.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
Two Fragments uses Navigation Drawer and in their respected fragments i am inflating menu buttons to sort items.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.sort_button_shops, menu);
}
Now the Problem is if i open the Fragment 1 it works perfectly. When i open fragment 2, it shows 2 button to sort, one from Fragment 1 and the second one from Fragment 2.
I have tried to hide the button but it didn't worked.
Any Help will be Appreciated.
Thanks
When you inflate a new menu you are adding new items to the old Menu object, which is probably not what you intended.
Try this:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.removeItem(R.id.your_menu_item);
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
Try using this in onResume() of fragments.
MenuItem item = (MenuItem) findViewById(R.menu.activity_main);
item.setVisible(false);
this.invalidateOptionsMenu();
In some methods of my Activity I want to check the title of menu or know if it is checked or not. How can I get Activity's menu. I need something like this.getMenu()
Be wary of invalidateOptionsMenu(). It recreates the entire menu. This has a lot of overhead and will reset embedded components like the SearchView. It took me quite a while to track down why my SearchView would "randomly" close.
I ended up capturing the menu as posted by Dark and then call onPrepareOptionsMenu(Menu) as necessary. This met my requirement without an nasty side effects. Gotcha: Make sure to do a null check in case you call onPrepareOptionsMenu() before the menu is created. I did this as below:
private Menu mOptionsMenu;
#Override
public boolean onCreateOptionsMenu(final Menu menu) {
mOptionsMenu = menu
...
}
private void updateOptionsMenu() {
if (mOptionsMenu != null) {
onPrepareOptionsMenu(mOptionsMenu);
}
}
Call invalidateOptionsMenu() instead of passing menu object around.
you could do it by passing the Menu object to your Activity class
public class MainActivity extends Activity
{
...
...
private Menu _menu = null;
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
_menu = menu;
return true;
}
private Menu getMenu()
{
//use it like this
return _menu;
}
}
There several callback methods that provide menu as a parameter.
You might wanna manipulate it there.
For example:
onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo)
onCreateOptionsMenu(Menu menu)
onCreatePanelMenu(int featureId, Menu menu)
There several more, best you take a look in activity documentation and look for your desired method:
http://developer.android.com/reference/android/app/Activity.html
As far as I could understand what you want here is which may help you:
1. Refer this tutorial over option menu.
2. Every time user presses menu button you can check it's title thru getTitle().
3. Or if you want to know the last menu item checked or selected when user has not pressed the menu button then you need to store the preferences when user presses.
Android now has the Toolbar widget which was a Menu you can set/get. Set the Toolbar in your Activity with some variation of setSupportActionBar(Toolbar) for stuff like onCreateOptionsMenu from a Fragment for example. Thread revived!
I use a sherlockfragmentactivity which has a ViewPager, two Fragment and an ActionBar displaying two tabs. I populate the actions items from the fragment but i have to call the method
setHasOptionsMenu(true);
in order than the fragment display the Actionbar MenuItem.
But when the screen oriention change, the MenuItems are not displayed.
Here is my code to create a option menu in my first fragment :
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.add(R.string.action_refresh).setIcon(R.drawable.ic_menu_refresh)
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
refresh();
return false;
}
}).setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(R.string.action_add_a_file).setIcon(R.drawable.ic_menu_upload)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM);
menu.add(R.string.action_settings).setIcon(android.R.drawable.ic_menu_preferences)
.setIntent(new Intent(getSherlockActivity(), SettingsActivity.class))
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_NEVER | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}
Is there a way to properly add item to the action bar from a SherlockFragment and how can i keep these item in ActionBar after screen orientation change ?
add following line in your FragmentActivity in the manifeast file
android:configChanges="orientation"
orientation is automatically handled by the system itself. but i don't know weather it is a efficient way or not.