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.
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 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();
In my application the main activity hosts two fragments and attached to acticity as ActionBarTabs. using the following code. NOTE: activity and the 2 fragments are defined in seperate xml layout files (See the picture at the bottom)
private void createActionTabs() {
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Status Tab
String strStatus = getResources().getString(R.string.lblStatus);
ActionBar.Tab statusTab = actionBar.newTab();
statusTab.setText(strStatus);
TabListener<SFrag> sFTabListener = new TabListener<SFrag>(this, strStatus, SFrag.class);
statusTab.setTabListener(sFTabListener);
actionBar.addTab(statusTab);
//Controller Tab attached the same way
.....
}
The ActionBar Items (start and refresh) are added using
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
Now coming to my problem:
I want to update the data shown on the Status Fragment at application load, fragment resume and click of refresh menu item from the action bar. Now when I try to access the Status fragment from Main Activity using the following code
SFrag frag = (SFrag) getFragmentManager().findFragmentById(R.id.st_frag);
Log.d(TAG, "In Activity SFrag is " + (frag == null ? "null" : "not null"));
if (frag != null) {
//calls the method to update data
fragment.updateStatusData(statusInformation);
}
The getFragmentManager().findFragmentById methods always returns null. I even tried the onResume method of the activity, the fragment objects is still returned as null. So how do I access the fragment and thus accessa method of that fragment from host acticty.
Secondly, I am trying to use the action_service (its shown as Start button just for this mockup) in action bar as a toggle for satrting or stopping a background service. I can easily update the title/icon for start menu item from onOptionsItemSelected method (I save the current status running/stoppede in shared-preferences). but when I try to accees the menuItem at onStart/onResume of the activity by using
MenuItem mi = (MenuItem) findViewById (R.id.action_service);
it always returns null. So How Can I access action_service menu Item in onResume/onStart to update it.
My Application looks like this
First of all if you want to declare MenuItem, you should do it in this way :
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.main_activity, menu);
MenuItem mRefresh = menu.findItem(R.id.refresh_menu_item);
return true;
}
About updating your Fragment on applications load or Activity's start, just set selected the tab which holds your Fragment and put the code which will load the data in your Fragment on it's onStart() or onActivityCreated() method. You can override onOptionsItemSelected() in your Fragment, so you can update your views not from your Activity which holds your Fragment, but from it's own class.
Edit: Here is an example how you should handle menu from your Fragment :
public class MyFragment extends Fragment {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true); // Do not forget this!!!
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.first_fragment, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case R.id.action_refresh:
// Do You stuff here
break;
}
return super.onOptionsItemSelected(item);
}
}
Using this you can add and use MenuItem's in your Fragment.
Hope this helps!
I can answer the MenuItem part just not the other part.
for the menu item as per 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.
for example
#Override
public boolean onCreateOptionsMenu(Menu menu) {
actionMenu = menu;
return true;
}
so basically anytime you want to change one of the items you can do this
MenuItem item = actionMenu.getItem(0);
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);
}
I found an example how to use a context menu with actionBar. This example waits for clicks on the phones menu button. But I want to have it appended to the icon or better the activity name. thanks
public class menu extends Activity {
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_fragen, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
..
After the logo and title comes an drop down menu indicator.
That has nothing to do with onCreateOptionsMenu() or onOptionsItemSelected(). To set up that Spinner:
Get your ActionBar via getActionBar()
Call setNavigationMode(ActionBar.NAVIGATION_MODE_LIST) on the ActionBar
Call setListNavigationCallbacks() on the ActionBar with your SpinnerAdapter and a listener object to be notified when the user makes a selection change in the Spinner