Currently, I am working on a new android project.
In my project, I have 2 FrameLayout (called F1, F2) which are used as containers of Fragment.
On "F1" I will add a fragment (Like navigation drawer fragment, menu item....).
On "F2" I called its MainContainer - It's will use container all "Main" fragment. (I mean F2 will container fragment like HomeFragment, GameFragment......).
Here are some steps:
F1 -> add fragment f1;
F1 -> add fragment f2;
F2 -> add fragment g1;
F2 -> add fragment g2;
F1 -> add fragment f3;
Now I want to use the transaction fragment on Container F2.
I mean:
I can add/remove a fragment on Container F2. But in android Fragment Manager will manager all Fragment f1..f3, g1..g2;
So I called popBackStack -> It's will remove fragment f3. (But I want to remove g2).
For any task like addFragment, remove, replace fragment I only want to do Fragment in Container F2. (F1 will be never changed).
Please help!
When you adding the fragment, you can use addToBackStack(String name) and disallowAddToBackStack() to control the back stack of FragmentManager.
For your requirement, you should use the code like this to add f1, f2, and f3:
getFragmentManager().beginTransaction()
.add(R.id.F1, [your fragment instance])
.disallowAddToBackStack()
.commit();
And use the code like below to add g1 and g2:
getFragmentManager().beginTransaction()
.add(R.id.F2, [your fragment instance])
.addToBackStack(null)
.commit();
Check the officail document of addToBackStack(String name) and disallowAddToBackStack() for more details.
You should use child fragment when adding child to that fragment.
public void addFragB() {
FragmentManager childFragMan = getChildFragmentManager();
FragmentTransaction childFragTrans = childFragMan.beginTransaction();
FragmentClassB fragB = new FragmentClassB();
childFragTrans.add(R.id.fragA_LinearLayout, fragB);
childFragTrans.addToBackStack("B");
childFragTrans.commit();
}
And when removing the fragment
public void backPressed() {
int childCount = parentFragment.getChildFragmentManager().getBackStackEntryCount();
if (childCount == 0) {
// it has no child Fragment
} else {
// get the child Fragment
FragmentManager childFragmentManager = parentFragment.getChildFragmentManager();
// removing the child Fragment from stack
childFragmentManager.popBackStackImmediate();
}
}
Related
Imagine i have main activity that has viewpager. I have 2 fragments called (F1 & F2) that will transaction into viewpager.
Again imagine in F1 fragment i want to set a button. When clicking on button, i want to transaction other fragment call SUBF1 but not into F1 fragment.
My question is here!!! Is it possible to replace SUBF1 with it's parent means F1?My idea is that i want to replace sub fragment with it's parent fragment that has been kept on fragment's container in main activity?
final FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, new NewFragmentToReplace(), "NewFragmentTag");
ft.commit();
You can save the instance of current fragment, when you are
navigating from one fragment to other. When user press the back
button, you can open the specific fragment with the help of tag.
#Override
public void onBackPressed() {
String currentTag = currentFragment.getTag();
if(currentTag.equals(res.getString(R.string.fragmentTagTest)))
{
currentFragment = AnotherFragment;
replaceFragment() // integrate replace current fragment with new one.
}
}
My app has this flow
Activity (TabLayout) -> Fragment 1 -> Fragment 2 -> Fragment 3
When I either press back on Fragment 2 or Fragment 3, I already go back to Fragment 1. I want to go back to Fragment 2 if I am on Fragment 3.
From fragment 1 to fragment 2
Frag2 childFrag = new Frag2();
getChildFragmentManager().beginTransaction().add(R.id.frag2_frame, childFrag)
.addToBackStack(null)
.commit();
From fragment 2 to fragment 3
Frag3 childFrag = new Frag3();
getChildFragmentManager().beginTransaction().add(R.id.frag3_frame, childFrag)
.addToBackStack(null)
.commit();
onBackPressed in Activity
// a fragments list for tablayout
ArrayList<Fragment> fragments = new ArrayList<>();
public void onBackPressed(){
fragments.get(selectedTab).getChildFragmentManager().popBackStack();
}
Try adding backStack
Frag2 childFrag = new Frag2();
getFragmentManager().beginTransaction().add(R.id.frag2_frame, childFrag)
.addToBackStack("Frag2 ")
.commit();
Once fragment 1 is added to the Activity, I believe you'll need to use getChildFragmentManager() to add additional fragments from a fragment. This method is available to classes that extend a Fragment.
Edit
As you've said you are using getChildFragmentManager(), I would use .beginTransaction().replace(...) instead of .beginTransaction().add(...).
Try to find the deepest fragment. Then popBackStack right there.
List<Fragment> fs2 = fragments.get(selectedTab).getChildFragmentManager().getFragments().get(0).getChildFragmentManager().getFragments();
FragmentManager f = fragments.get(selectedTab).getChildFragmentManager();
while (fs2.size() > 0) {
fs2 = fs2.get(0).getChildFragmentManager().getFragments();
f = f.getFragments().get(0).getChildFragmentManager();
}
f.popBackStack();
I have a Activity where I load 3 fragments one after another
FragmentA
FragmentB
FragmentC
Flow is Like this I have used Adding fragment one above another
Start-Activity -----> Load FragmentA ----> Load FragmentB ----> Load FragmentC
What I am trying to do now is:
Now assuming now FragmentC is the top fragment shown
I want to find the FragmentA from the stack and just show it instead of creating a fragmentA all over again
Code I have used to add fragmentA is for Example:
Fragment fragment = null;
FragmentTransaction fragmentTransaction = null;
fragment = new FragmentA();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.addToBackStack(FragmentA.class.getSimpleName());
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
fragmentTransaction.add(R.id.container, fragment, FragmentA.class.getSimpleName());
if(fragment!=null && fragmentTransaction!=null){
fragmentTransaction.commitAllowingStateLoss();
}
Look at FragmentManager.getBackStackEntryAt method, from there you can go back to any fragment of your history…
Loop through the back stack entries, meanwhile, if you find any matching Fragment by id or tag, just pop back stack inclusive with fragment A's name/tag so that the fragment A is just displayed rather than adding once again.
The example code to retrieve a fragment by Tag would look like this
FragmentA frA = getSupportFragmentManager().findFragmentByTag(FragmentA.class.getSimpleName());
and if it's not null you can reuse it in your container
if(frA != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
//you could add this transactionn to backstack again here if you want to be able to pop it later
fragmentTransaction.add(R.id.container, frA, FragmentA.class.getSimpleName());
} else {
//if your fragment is null as it was destroyed previously you can create a new one here
}
You are giving a tag, fragmentTransaction.addToBackStack(FragmentA.class.getSimpleName()); to the transaction , you can use the same tag to find the fragment in the backstack, before creating a new frgament, check the backstack for the fragment using findFragmentByTag on the fragment manager, if it exist, the method returns the fragment otherwise null
try it!
val fm: FragmentManager? = fragmentManager
for (entry in 0 until fm.getBackStackEntryCount()) {
Log.i(TAG, "Found fragment: " + fm.getBackStackEntryAt(entry).getId())
}
Currently, I have a Fragment stack like this.
F1 -> F2 -> F3 -> F4 -> F5
And in an activity, I have one button B1.
My question is when I press B1 button from the activity how can I update Fragment stack like below.
F2 -> F3 -> F4 -> F5 -> F1.
I have used string tags at the time of addtobackstack.
You can solve this problem by using Stack in your code. And in fragment transaction, you have to use add instead of replacing the fragment. On button B1 press you have to pop fragment F1 from the stack and again you have to push it to the stack. I thought it may be work for you.
I solved this by this code:
public void fragmentInflater(Fragment newFragment) {
FragmentTransaction transaction;
FragmentManager fragmentManager = getSupportFragmentManager();
transaction = fragmentManager.beginTransaction();
Fragment oldFragment = fragmentManager.findFragmentByTag(newFragment.getClass().getName());
if (oldFragment == null) {
transaction.replace(R.id.container, newFragment, newFragment.getClass().getName());
transaction.addToBackStack(null);
} else {
transaction.replace(R.id.container, oldFragment, newFragment.getClass().getName());
}
transaction.commit();
}
Use this method for adding fragments to your container and you will achieve what you want. It will also prevents adding duplicated fragments to your container.
I have a problem about removing a specific fragment from back stack.My scenario is like this.Fragment-1 is replaced with Fragment-2 and then Fragment-2 is replaced with Fragment-3.
Calling order; Fragment-1-->Fragment-2-->Fragment-3.
When Fragment-3 is on the screen and then back button is clicked, i want to go
Fragment-1.That means i want to delete Fragment-2 from back stack.
How to do this ?
In the backstack you don't have Fragments, but FragmentTransactions. When you popBackStack() the transaction is applied again, but backward. This means that (assuming you addToBackStackTrace(null) every time) in your backstack you have
1->2
2->3
If you don't add the second transaction to the backstack the result is that your backstack is just
1->2
and so pressing the back button will cause the execution of 2->1, which leads to an error due to the fragment 2 not being there (you are on fragment 3).
The easiest solution is to pop the backstack before going from 2 to 3
//from fragment-2:
getFragmentManager().popBackStack();
getFragmentManager().beginTransaction()
.replace(R.id.container, fragment3)
.addToBackStack(null)
.commit();
What I'm doing here is these: from fragment 2 I go back to fragment 1 and then straight to fragment 3. This way the back button will bring me again from 3 to 1.
I had a very similar scenario to yours, my solution was just checking the amount of backStack transactions that I had.
If the transactions where more than 0 then I would simply pop it right away
so it would skip it when pressing back.
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
}
...
fragmentTransaction.replace(R.id.main_fragment, newFrag, MAIN_FRAGMENT_TAG);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.commit();
This would successfully:
A -> B (back pressed) -> back to A
A -> B -> C (back pressed) -> back to A
The only downside that I see is that there is a quick flash where fragment A is displayed before going to fragment C.
If you are adding/launching all three fragments in the same activity, instead of the add(), use replace() (replace Fragment2 with Fragment3). The replace method removes the current fragment from backstack before adding the new one. If you are launching Fragment3 from a different activity, and thus you can't use replace(), remove Fragment2 from backstack before starting the new activity (which adds Fragment3):
// in Fragment2, before adding Fragment3:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.remove(this) // "this" refers to current instance of Fragment2
.commit();
fragmentManager.popBackStack();
// now go ahead and launch (add) fragment3
// if fragment3 is launched from a different activity,
// start that activity instead
fragmentManager.beginTransaction()
.add(R.id.a_container_view_in_activity, new Fragment3(),
Fargment3.FRAGMENT3_ID)
.commit();
Code for Fragment A -> Fragment B:
Add Fragment A in BackStack of Fragments
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_container, new fragmentB());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Code for Fragment B -> Fragment C:
Do not Add Fragment B in BackStack of Fragments
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_layout_container, new fragmentC());
fragmentTransaction.commit();
It will works in this way: A -> B -> C and while returning C-> A as you excepted.
Hope it will help you.
for (int i = 0; i < mFragmentManager.getBackStackEntryCount(); i++) {
currentFragment = mFragmentManager.getFragments().get(i);
if (!(currentFragment instanceof ParticularFragment))
mFragmentManager.popBackStack();
else
break;
}