I have a navigation drawer that works well. By well I mean I can navigate through all the fragments tied to the Navigation drawer (A,B,C,D). My issue arises here. Lets say am in Fragment A, in this fragment I have a button which on clicking should ideally replace the fragment with another one say Frag Z, and once I am in Frag Z I can return back to frag A.
To achieve this I use the below code. However the new fragment Z appears transparent on top of Fragment A. What could be the problem:
Bundle bundle = new Bundle();
bundle.putInt("int", 1);
bundle.putString("str","string" );
fragmentTransaction = getFragmentManager().beginTransaction();
FragZ fragmentz = new FragZ();
fragment.setArguments(bundle);
fragmentTransaction.replace(R.id.some_container, fragmentz);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
EDIT:
I have found a workaround to this as shown below,however it does not completely solve my problem since the newly displayed fragment is still shown with the navigation drawer capable of being toggled,but it atleast removed the overlaying of the fragments. I would still want a solution to launching an independent fragment
Bundle bundle = new Bundle();
bundle.putInt("int", 1);
bundle.putString("str","string" );
FragZ fragmentz = new FragZ();
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
fragment.setArguments(bundle);
ft.replace(R.id.main, fragment);
ft.addToBackStack(null);
ft.commit();
Create a method in your activity to launch fragments. Whenever you want to display the fragment, just call in with a number or string to represent the fragment. You can use the same function to launch fragments from your navigation drawer.
For example:
public void displayView(int position) {
Fragment fragment = null;
currentFragmentNumber = position;
switch (position) {
case 0:
fragment = new frag1();
break;
case 1:
fragment = new frag2();
break;
case 2:
fragment = new frag3();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment)
.addToBackStack("tag").commit();
} else {
// error in creating fragment
Log.e(TAG, "Error in creating fragment");
}
}
You can call this function from your activity by using:
((**ActivityName**) getActivity()).displayView(0);
Related
i have 2 fragments (1,2).
after a button click on (fragment 1) transition happens to (fragment 2) .now from (fragment 2) if a button is clicked i go to the (new_activity ).my problem is when i return from (new_activity) i want to go back to (fragment 2) & then to (fragment 1) but it directly goes to fragment 1 .i am not able to add (fragment 2) to the addTOBackStack.
// method to handle click event of category
public void onClick(View v) {
FragmentManager fragmentManager = getActivity()
.getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
Bundle bundle = new Bundle();
int categoryId;
CategoryFragment a = new CategoryFragment();
Log.d("HomeFragment", v.getId() + "");
switch (v.getId()) {
case R.id.image_american_chiffon:
categoryId = 1;
bundle.putInt("categoryId", categoryId);
a.setArguments(bundle);
ft.replace(R.id.contentFrame, a);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
break;
case R.id.image_nagma:
categoryId = 2;
bundle.putInt("categoryId", categoryId);
a.setArguments(bundle);
ft.replace(R.id.contentFrame, a);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
break;
}
ft.commit();
Log.e("BACK STACK COUNT",fragmentManager.getBackStackEntryCount()+"");
}
Everytime you call replace method,new object of that fragment is being created.You can add all needed fragments at the beginning in the hidden state and then just show and hide according to your need.so you don't need to initialize everytime,just have to display the required fragment and hide the other fragment.
To Add fragment at the begining,do like this:
Fragment myFragment = new CategoryFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.fragmentContainer, myFragment, SOME_TAG);
transaction.hide(myFragment);
transaction.commit();
and Instead of calling replace() method,just hide and show the desired fragment
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.show(getFragmentManager().findFragmentByTag(fragmentTagToBeShown));
transaction.hide(getFragmentManager().findFragmentByTag(currentFragmentTag));
transaction.commit();
I have implemented a navigation drawer in my application, The application is a tabbed layout and I think this is where the problem is coming from.
AT the moment I have a listener on the items in the Nav drawer to launch a new fragment when pressed. The issue is that when I press one of the items the fragment doesnt seem to load and the current fragment just goes blank.
How do I set the layout of the fragment to launch once the item has been selected? As my current method doesnt seem to be working. The below shows my current attemp where R.id.viewpager is what I am trying to replace. Is there a way of just launching the fragments layout and completely replacing the layout with the new fragments layout?
onDrawerItemSelected
#Override
public void onDrawerItemSelected(View view, int position) {
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (position)
{
case 0:
{
Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);
}
case 1:
fragment = new FavouritesFragment();
title = getString(R.string.title_favourites);
break;
case 2:
fragment = new HelpFragment();
title = getString(R.string.title_help);
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.viewpager, fragment);
fragmentTransaction.commit();
// set the toolbar title
getSupportActionBar().setTitle(title);
}
}
fragmentTransaction.replace(R.id.viewpager, fragment);
You don't replace the viewpager, you set current item for the viewPager. You should have a PagerAdapter that defines which fragment to show for the position.
okay i know there are other questions that on first glance make this one look like a duplicate, but none of these answers work in my case,
What i want is the first fragment displayed to be like a Main Activity in respect to how the back button works, i need whichever fragment i choose from my navigation drawer to go back to the first fragment when the back button is pressed then a user would quit the app by pressing it again.
So ive tried using addToBackStack and when i move to another fragment if i press the back button it comes back to my first fragment (exactly as i want) but pressing the back button again leaves me with a white screen (i wonder if this is due to the transaction animation im using which ive included below) so to get around this i tried overriding the back button and throwing in a call to finish(); but this causes whichever fragment im in to finish instead of going back to the first fragment, ive tried a handful of workarounds from the above mentioned link and many others but cannot find a decent fix any suggestions?
here is my Main Activity displayView
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new FirstFragment();
break;
case 1:
fragment = new glideFrag();
break;
case 2:
fragment = new secondGlideFrag();
break;
case 3:
fragment = new thirdGlideFrag();
break;
case 4:
fragment = new forthGlideFrag();
break;
case 5:
fragment = new lgFrag();
break;
case 6:
fragment = new cyanFrag();
break;
case 7:
fragment = new sonyFrag();
break;
case 8:
fragment = new SecondFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.enter,R.anim.exit,R.anim.pop_enter,R.anim.pop_exit);
//fragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.frame_container, fragment).addToBackStack("first 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 {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
i found this that looks like a great way around it
private boolean popNext = false;
if(popNext){
if(position == INITIAL_POSITION){
onBackPressed();
mDrawerLayout.closeDrawer(mDrawerList);
popNext = false;
return;
}
getSupportFragmentManager().popBackStackImmediate();
}
else{
if(position == INITIAL_POSITION){
mDrawerLayout.closeDrawer(mDrawerList);
return;
}
popNext=true;
}
but im still fairly new to android and im not sure what to set INITIAL_POSITION to, I tried
private static final INITIAL_POSITION = 0;
but without any luck
When adding the initial fragment, you must not add it to the back stack.
You must only do it for the next ones. When the back stack will be empty, the Activity will just finish.
Edit: Here is an explanation of the problem so you can figure out how to fix it:
Each time you add a fragment transaction to the back stack, you allow the user to revert it by pressing the back button and the Activity will return to the state it was before the transaction. If the initial fragment is added to the back stack, then when the user press back, the screen becomes blank, because there was nothing displayed before you added the initial fragment. That's why the initial fragment transaction which adds the first visible fragment to your Activity must not be added to the back stack. Usually you initialize the initial fragment like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
Fragment fragment = new FirstFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.frame_container, fragment)
.commit();
}
}
BladeCoders answer was more trying to tell me how the backstack works rather than answering my question, i ended up not adding any fragments to the back stack, .addToBackStack(null), and overriding back button in MainActivity, feels like a little bit of a hack but works perfectly
#Override
public void onBackPressed() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() < 1){
Fragment fragment = new FirstFragment();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.enter, R.anim.exit,
R.anim.pop_enter, R.anim.pop_exit);
getSupportActionBar().setTitle(mDrawerTitle);
fragmentTransaction.replace(R.id.frame_container,
fragment).addToBackStack("first").commit();
}else{
finish();
}
}
You can do it even with out backstack its just my point of view to simplify so that it can help some one.
#Override
public void onBackPressed(){
Fragment f = getSupportFragmentManager().findFragmentById(R.id.container_body);
if(f.getClass().getName().equals(HomeFragment.class.getName())){ // here HomeFragment.class.getName() means from which faragment you actually want to exit
finish();
}else{
displayView(0); //were you want to go when back button is pressed
}
}
private void displayView(int position) {
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (position) {
case 0:
fragment = new HomeFragment();
title = getString(R.string.app_name);
break;
case 1:
fragment = new OffersFragment();
title = getString(R.string.nav_item_offers);
break;
case 2:
fragment = new NotificationFragment();
title = getString(R.string.nav_item_notifications);
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container_body, fragment);
fragmentTransaction.commit();
// set the toolbar title
getSupportActionBar().setTitle(title);
}
}
I use a master/detail flow and in every fragment I have a viewpager containing some forms but the thing is when I click on some other links from the master list, the content of the viewpager is lost. How to save this content so everytime I click on the same choice I find my data.
My code :
#Override
public void onItemSelected(String id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
if(id.contains("1"))
{
Bundle arguments = new Bundle();
ItemDetailFragment fragment = new ItemDetailFragment();
fragment.setRetainInstance(true);
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.item_detail_container, fragment).commit();
}
else if(id.contains("2"))
{
Bundle arguments = new Bundle();
ItemDetailFragment2 fragment = new ItemDetailFragment2();
fragment.setRetainInstance(true);
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.item_detail_container, fragment).commit();
}
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_ITEM_ID, id);
startActivity(detailIntent);
}
}
EDIT:
I tried to modify my code this way :
if (id.contains("1")) {
Fragment currFragment = fm.findFragmentByTag(lastTag);
ItemDetailFragment newFragment = (ItemDetailFragment) fm.findFragmentByTag("f"+1);
FragmentTransaction ft = fm.beginTransaction();
ft.hide(currFragment);
if(newFragment==null)
{lastTag="f"+1;
newFragment=new ItemDetailFragment();
ft
.replace(R.id.item_detail_container, newFragment);}
else {
ft.show(newFragment);
}
ft.commit();
}
But i got a NullPointerException at android.support.v4.app.BackStackRecord.run(BackStackrecord.java:656)
Try to call setRetainInstance(true) in your fragments onCreate()
As writed here, if you do not add the transaction to the back stack, then the fragment is destroyed when removed or replaced.
You can hide current fragment, instead replacing, then add new. Like that:
int currPage = 0;
public void goToPage(int num) {
FragmentManager fm = getSupportFragmentManager();
Fragment currFragment = fm.findFragmentByTag("f" + currPage);
Fragment newFragment = fm.findFragmentByTag("f" + num);
FragmentTransition ft = fm.beginTransaction();
ft.hide(currFragment);
if(newFragment == null) {
// First use. Create new instance for page.
newFragment = new MyFragment();
ft.add(R.id.item_detail_container, newFragment, "f" + num);
} else {
// Fragment for page already added. Just show it.
ft.show(newFragment);
}
ft.commit();
this.currPage = num;
}
And don't forget to specify tag for initial page fragment too.
You can implement the onPause() or onStop() methods of your fragments and save the data when that methods are called, which happens automatically when they are removed.
Or you could perhaps go with the savedInstanceState.
It's better to save in the arrayList. Onclick store the image id in the arrayList.
Short version:
I have activity with fragment, which include ViewPager (with FragmentStatePagerAdapter) and on resume to this fragment it recreates. How can I by back press return to Fragment and restore is state and it's Viewpager?
Details:
I have an activity with FrameLayout (R.id.themesFragmentsLayout), in activity's method onCreate(..) I do:
if (savedInstanceState == null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ThemesFragment fragment = new ThemesFragment();
fragmentTransaction.replace(R.id.themesFragmentsLayout, fragment, ThemesFragment.TAG);
fragmentTransaction.commit();
}
ThemesFragment include only ViewPager with FragmentStatePagerAdapter, which holds 3 fragments:
public Fragment getItem(int position) {
switch (position) {
case ID_THEME_PAST:
return new ThemePastFragment();
case ID_THEME_OF_DAY:
return new ThemeOfDayFragment();
case ID_THEME_UPCOMING:
return new ThemeUpcomingFragment();
default:
return null;
}
}
In ThemeOfDayFragment for example, user can click some button and I change ThemesFragment (which holds ViewPager) with some another (for example ThemeDetails):
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(newFragment.getClass().getSimpleName());
fragmentTransaction.replace(((AboutMyStyleApplication) getActivity().getApplication()).getCurrentFragmentsLayoutId(), newFragment, newFragment.getClass().getSimpleName());
fragmentTransaction.commitAllowingStateLoss(); // or fragmentTransaction.commit(); - same result
But when he came back (by back key press for example) ThemesFragment recreates, and all fragments in ViewPager recreates to.
In ThemesFragment I set setRetainInstance(true)
Can anyone help?