I was working my way through the NavigationDrawer sample code from developer.android.com and tried to implement it as navigation for one of my apps. However, I came across a problem when it came to switching fragments in the main window, as the sample code reuses the same fragment and just switches out an imageview. Here is the code from the sample:
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
// update the main content by replacing fragments
Fragment fragment = new PlanetFragment();
Bundle args = new Bundle();
args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
fragment.setArguments(args);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
where PlanetFragment is a generic fragment with only an imageview and no functionality, which does not apply for my app. So, instead, I tried and replaced the first block of the selectItem method with a case/switch:
public void selectItem(int position){
Fragment fragment;
switch(position){
case 1: fragment = new Fragmentscreentest(); break;
case 2: fragment = new Fragmentstatusbar(); break;
case 3: fragment = new Fragmentfullscreen(); break;
default: fragment = new Fragmentscreentest(); break;
}
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
and added the same empty constuctor to my Fragments as the PlanetFragment has:
public Fragmentstatus() {
// Empty constructor required for fragment subclasses
}
It doesn't work, whenever I open up the app, it only shows the app icon and the title in the actionbar, no content, no actions on the actionbar, no navigation drawer, nothing and then it crashes after about a second. With the original code it works and shows everything, but that only works for one fragment.
How can I actually switch Fragments in the NavigationDrawer?
Take a look at my code:
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
switch (position) {
case 0:
fragmentManager.beginTransaction()
.replace(R.id.content_frame, new MainActivityFragment())
.commit();
break;
case 1:
fragmentManager.beginTransaction()
.replace(R.id.content_frame, new DbListViewFragment())
.commit();
break;
case 2:
fragmentManager.beginTransaction()
.replace(R.id.content_frame, new StatisticsFragment())
.commit();
break;
case 3:
fragmentManager.beginTransaction()
.replace(R.id.content_frame, new CalculatorFragment(), "calculator")
.commit();
break;
}
I am using a switch-case. position 0 is the very first item in my ListView inside the drawer.
Taken from my answer on this question: DrawerLayout on click disabled after first event
EDIT:
If you want to select one Fragment at start you can do it like this at the end of your onCreate method:
if (savedInstanceState == null) {
selectItem(0);
}
0 being the position of your desired Fragment
Related
This is how I used navigation drawer to display Fragments:
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new Fragment0();
break;
case 1:
fragment = new Fragment1();
break;
case 2:
fragment = new Fragment2();
break;
case 3:
fragment = new Fragment3();
break;
case 4:
fragment = new Fragment4();
break;
case 5:
fragment = new Fragment5();
}
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack(null)
.commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(drawerll);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Suppose if the user navigates to Fragment 2-> Fragment 5-> Fragment3.
If the user clicks the back button I need to have the descending order and on each fragment I am displaying the name of the Fragment when he goes to that particular fragment ie:
Fragment 3-> Fragment 5-> Fragment2.
This is what I have tried:
First Method:
FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
fm.popBackStackImmediate();
}
Second Method:
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
I'm unable to get this working**(ie.. I'm unable to move it back to the fragment where I have come from**) and unable to display the name of the fragment based on the backstack
Any help is greatly appreciated.
Your navigation is working fine I guess and the issue you are facing is the tittle for which you can use
public class SampleFragment extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Creating view correspoding to the fragment
View v = inflater.inflate(R.layout.fragment_layout, container, false);
// Updating the action bar title
getActivity().getActionBar().setTitle("Screen name");
return v;
}
}
in every fragment. And whenever you backpress the onCreateView method of fragmemt(the one which is poping from the backstack) gets called and the tittle will again set replacing the old tittle.
1. Handle back
You can use getSupportFragmentManager().popBackStack() method in onBackPressed:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
getSupportFragmentManager().beginTransaction().commit();
}
else {
super.onBackPressed();
}
}
Don't forget to add the fragment in BackStack like :
transaction.addToBackStack(null);
2. Display Name
To show the current fragment name in actionbar, you can get it on onResume of your Fragment :
#Override
protected void onResume() {
super.onResume();
((FrgmentActivtiyName)getActivity).changeTitle("title");
}
Define a method which set the title in the actionbar in your FrgmentActivity:
public void changeTitle(String titleToSet) {
// set title as titleToSet
}
Hope it helps ツ
Please try this:
In the activity which holds the fragments, override the onbackPressed() method by,
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
getSupportFragmentManager().beginTransaction().commit();
}
else {
super.onBackPressed();
}
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
menuList.setItemChecked(position, true);
menuList.setSelection(position);
}
In my navigation drawer I have to selections: 1)Laptop 2)Desktop
How can I open another fragment when I click on Desktop? Sorry, I am new in Android Programming
I have also visited the other questions about this in stackoverflow, but they still do not work
Thanks
public void onNavigationDrawerItemSelected(int position) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
switch (position){
case 0:
fragment = new FragmentLaptop();
break;
case 1:
fragment = new FragmentDesktop();
break;
}
transaction
.replace(R.id.container, fragment)
.commit();
}
onNavigationDrawerItemSelected(position)needs to be called in onItemClick(...) where you have the listener of the list
like this:
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
onNavigationDrawerItemSelected(position);
}
I am implementing navigation drawer and works well. So i am calling fragment on navigation drawer click and it is also working and further more i am calling another fragment from Home page fragment and maintain the back stack for every fragment but the problem is back press from the child fragment i can't go to Home page fragment and just exited from application. I don't want this. What i want Click on
Navigation Drawer->HomePageFragment->AnotherChild Fragment(On List Item click of HomePageFragment)
but on back pressed without going to Homepage fragment its directly exit with application. Here is my code: (In Fragment Activity with Navigation Drawer)
class SlideitemListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
updateDisplay(position);
}
}
private void updateDisplay(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new ScheduleFragment();
break;
case 1:
fragment = new Result_Fragment();
break;
case 2:
fragment = new Live_Match_Fragment();
break;
case 3:
// fragment = new Live_Match_Fragment();
break;
case 4:
fragment = new Team_Fragment();
break;
default:
break;
}
if (fragment != null) {
fragmentManager = getFragmentManager();
fragmentManager.popBackStackImmediate("0", 0);
int count = fragmentManager.getBackStackEntryCount();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(String.valueOf(count)).commit();
Log.e("Count in Activiy", ""+count);
// update selected item and title, then close the drawer
setTitle(menutitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Now in BackPressed() in FragmentActivity.
#Override
public void onBackPressed() {
if (fragmentManager.getBackStackEntryCount() <= 1) {
finish();
return;
}
super.onBackPressed();
}
Now calling another child fragment from HomePage fragment on Listview item click.
team_lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
TeamDetailFragment myDetailFragment = new TeamDetailFragment();
FragmentManager fragmentManager = getFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
Log.e("Count in Fragment", "" + count);
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction
.replace(R.id.frame_container, myDetailFragment)
.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(String.valueOf(count)).commit();
}
});
So anybody knows then help me. Help will be appreciate.
There is an issue with nested fragments in android
https://code.google.com/p/android/issues/detail?id=40323
Android doesn't handle back press well if transactions were in nested fragments.
To surpass this i am using the following fix inside My Activity
#Override
public void onBackPressed() {
// If the fragment exists and has some back-stack entry
if (myFragment != null && myFragment.getChildFragmentManager().getBackStackEntryCount() > 0) {
// Get the fragment fragment manager - and pop the backstack
myFragment.getChildFragmentManager().popBackStack();
}
// Else, nothing in the direct fragment back stack
else {
// Let super handle the back press
super.onBackPressed();
}
}
I've solved in the following way:
1st solution
#Override
public void onBackPressed() {
FragmentManager fragmentManager = getFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
if(backCount > 1) {
super.onBackPressed();
} else {
finish();
}
}
2nd solution
#Override
public void onBackStackChanged() {
FragmentManager fragmentManager = getFragmentManager();
int backCount = fragmentManager.getBackStackEntryCount();
if(backCount == 0) {
finish();
}
}
These allow you to exploit the Android stack when you replace your fragment:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, yourFragment)
.addToBackStack(null).commit();
When you press back button inside your fragment onBackPressed() method of your activity will be called if you have declared that..So handling back button for fragments within navigation drawer can be one in this way..
MainActvity
public static boolean isMainActivityShown ;
public static boolean isFragment1Shown=false ;
public static boolean isFragment2Shown=false ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isMainActivityShown=true //inside onCreate method put isMainActivityShown true
.
.
.
{
Fragment currentFragment = new Fragment1();
isMainActivityShown=false; //when moving to fragment1
isFragment1Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
}
.
.
}
#Override
public void onBackPressed() {
if(isMainActivityShown)
{
finish();
}
else if(isFragment1Shown)
{
//write the code to handle back button when you are in Fragment1
}
else if(isFragment2Shown)
{ //When you are in Fragment 2 pressing back button will move to fragment1
Fragment currentFragment = new Fragment1();
isFragment2Shown=false;
isFragment1Shown=true;
FragmentManager frgManager;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
}
}
Fragment1
Fragment currentFragment = new Fragment2();
MainActivity.isFragment1Shown=false;
MainActivity.isFragment2Shown=true;
frgManager = getFragmentManager();
frgManager.beginTransaction().replace(R.id.content_frame, currentFragment)
.commit();
Now you can replace finish() for fragmentManager.popBackStack(), method of android.support.v4.app.FragmentManager
I have an ActionBarActivity that has a Navigation Drawer. When opening the app, the default fragment shown is Fragment A.
Fragment B (which is another selection on the nav drawer), there is a ListView that when clicked on an item, will open Fragment C in the same container. When I am pressing the back button in Fragment C, instead of going to Fragment B, it goes to Fragment A.
Also, when I click on an item in the nav drawer, I clear the entire backstack. Not sure if I am doing this right either. I have included the code below.
Can't figure why this is happening!
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) { showExitDialog(); }
else { super.onBackPressed(); }
}
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fm = getSupportFragmentManager();
switch (position) {
case 0: // User Profile
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fm.beginTransaction().replace(R.id.container,
ProfileFragment.newInstance(GlobalMethods.readCurrentUserObject(this)),
"profileFragment").commit();
return;
case 1: // Find Match
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fm.beginTransaction().replace(R.id.container, DashboardFragment.newInstance(), "dashboardFragment").commit();
return;
case 2: // Match Settings
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fm.beginTransaction().replace(R.id.container, MatchSettingsFragment.newInstance(),
"matchSettingsFragment").commit();
return;
case 3: // Previous Matches
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fm.beginTransaction().replace(R.id.container, PreviousMatchesFragment.newInstance(),
"previousMatchesFragment").commit();
return;
case 4: // Messages
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fm.beginTransaction().replace(R.id.container, LatestMessagesFragment.newInstance(),
"latestMessagesFragment").commit();
return;
case 5: // Settings
return;
case 6: // Log Out
startActivity(new Intent(this, LoginActivity.class));
finish();
return;
}
}
UPDATE 1
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
FragmentManager fm = getActivity().getSupportFragmentManager();
android.support.v4.app.FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container, ProfileFragment.newInstance(users.get(position)), "profileFragment");
ft.addToBackStack(null);
ft.commit();
}
});
Try this:
ft.add(R.id.container, ProfileFragment.newInstance(users.get(position)), "profileFragment");
ft.addToBackStack(reference to B);
This is one of the method() of Navigation Drawer activity...
Code Snippet:
/**
* Diplaying fragment view for selected nav drawer list item
**/
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new ViewFragment();
break;
case 1:
//here i should call the FragmentActivity
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// Log.e("MainActivity", "Error in creating fragment");
}
}
create intent with fragment activity and use startActivity() to launch the fragment Activity.
switch (position) {
case 0:
fragment = new ViewFragment();
break;
case 1:
//here i should call the FragmentActivity
Intent intent = new Intent(Context, FragmentActivity.class);
startActivity(intent);
default:
break;
}
But make sure that your FragmentActivity. In FragmentActivity you have to use fragment to display the content.