My flow of fragment is like this
Main -> A -> B -> C ->A
In fragment c, it has a submit button which will return to A.
When I press back button in A, I want it back to Main. But it return to fragment c instead.
In fragment C, I use this
findNavController().navigate(R.id.action_c_to_a)
nav_graph.xml
<fragment
android:id="#+id/fragmentC"
android:name="xxx"
android:label="xxx">
<action
app:launchSingleTop="true"
app:popUpTo="#+id/fragmentA"
app:popUpToInclusive="true"
android:id="#+id/action_c_to_a"
app:destination="#id/fragmentA" />
</fragment>
Why not pop up to fragment A? You could just call findNavController().popBackStack(R.id.fragmentA, false) instead of navigating with an action.
try to look at my complete solution with removing/killing fragment from backstack.
Navigation Component set transition animation programmatically
You can override the back button behavior to do this.
Provide custom back navigation
The idea is to set a app:popUpTo without setting app:destination. Indeed, setting a app:destination will create a fragment and add it to the backstack which is not what you want.
To you can just remove :
app:destination="#id/fragmentA"
If you have this :
app:popUpTo="#+id/fragmentA"
And it will really pop the backstack until fragmentA
Related
Here is scenario:
On login activity button click open Activity 2
In Activity 2 multiple fragments and navigate through navgraph
I want to go back on login screen while click on Fragment 3 Finish button
Here what I try but no luck:
findNavController().navigate(
R.id.action_fragment3_to_fragment1,
null,
NavOptions.Builder()
.setPopUpTo(R.id.fragment1, true).build())
You need to close Activity 2 using finish() and the fragments will be closed with the activity, to close Activity 2 from Fragment 3 you can use this line of code inside Fragment 3:
requireActivity().finish()
First, add attributes app:popUpTo='your_nav_graph_id' and app:popUpToInclusive="true" to the action tag.
<fragment
android:id="#+id/signInFragment"
android:name="com.glee.incog2.android.fragment.SignInFragment"
android:label="fragment_sign_in"
tools:layout="#layout/fragment_sign_in" >
<action
android:id="#+id/action_signInFragment_to_usersFragment"
app:destination="#id/usersFragment"
app:launchSingleTop="true"
app:popUpTo="#+id/main_nav_graph"
app:popUpToInclusive="true" />
Second, navigate to the destination, using above action as parameter.
findNavController(fragment).navigate(
SignInFragmentDirections.actionSignInFragmentToUserNameFragment())
I've 2 fragments, A & B
with action:
<action
android:id="#+id/action_a_to_b"
app:destination="#id/b"
app:enterAnim="#android:anim/fade_in"
app:exitAnim="#android:anim/fade_out"
app:popEnterAnim="#android:anim/fade_in"
app:popExitAnim="#android:anim/fade_out"
app:popUpTo="#id/a"/>
after I move from a to b and pressing back,
and then try again to open b from a, the app crashes and the problem is that the navigation graph current destination remains fragment b instead of changing to a.
Update:
if fragment B inherit from Fragment class, it doesn't happen
if fragment B inherit from BottomSheetDialogFragment it does happen
any idea why?
Thanks.
The problem was that i used the tag instead of in the navigation graph...
I have a question. I'm using nav component for navigation. For example i have fragment A, B and C and bottomNavigation. I'm using
binding.bottomNavigation.setupWithNavController(navController)
For multiple backstack. But here is situation: Main frag is A. I'm moving to fragment B or C. I have buttons on fragments B and C which should lead me to fragment A with putted arguments in it so i'm using just:
findNavController().navigate(fragmentBDirections.fromFragmentBToFragmentA(argument))
But here is a problem. I'm recreating fragment A after this but i'm already have this fragment in backstack. So is it possible to find A in backstack and navigate to it without recreating? Is it possible to save backstack after that?
Your problem seems like an ideal case to use a sharedViewModel
Your button in B or C should pop and fallback to A after updating a property in the viewModel. On leaving, the viewModel is not destroyed because it is bound to the activity and is available for Fragment A.
Bonus is using LiveData so that the change is observed and updated automatically
I think SavedStateHandle might be helpful.
<Navigation>
<fragment
android:id="#+id/BFragment"
android:name="com.packageName.app.BFragment"
android:label="fragment_b"
tools:layout="#layout/fragment_b" >
<action
android:id="#+id/action_BFragment_pop_including_AFragment"
app:popUpTo="#id/AFragment"
app:launchSingleTop="true" />
</Navigation>
<Navigation>
<fragment
android:id="#+id/CFragment"
android:name="com.packageName.app.CFragment"
android:label="fragment_c"
tools:layout="#layout/fragment_c" >
<action
android:id="#+id/action_CFragment_pop_including_AFragment"
app:popUpTo="#id/AFragment"
app:launchSingleTop="true" />
</Navigation>
try it . it's my solution
I couldn't find anything online so here I am. I'm using the jetpack navigation component and I want to navigate from fragmentA to fragmentB, and then fragmentB will navigate to fragmentC, but when pressing hw back button I want to go back straight to fragmentA. is this possible with the current release?
This can be done with adding popUpTo to your action where you move from B -> C.
<fragment
android:id="#+id/fragmentB"
android:name="com.ballboycorp.anappaday.navigationtest.FragmentB"
android:label="fragment_b"
tools:layout="#layout/fragment_b">
<action
android:id="#+id/action_fragmentB_to_fragmentC"
app:destination="#+id/fragmentC"
app:popUpTo="#+id/fragmentA" />
</fragment>
What that means is
From B move to C and when user clicks back button, move back to A.
You should navigation to C using that action instead of giving destination id.
button.setOnClickListener {
findNavController().navigate(R.id.action_fragmentB_to_fragmentC)
}
Visually this is how it looks
With the Navigation Component you can handle onBackPressed on fragments. In your onViewCreated of fragment C just add this line of code:
requireActivity().onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
view.findNavController().popBackStack(R.id.fragmentA, false)
}
})
I am using the new AndroidX navigation framework.
I have a few fragments all linked in a navigation chain.
FragmentA --> FragmentB --> FragmentC
FragmentC has a Cancel button that should send me up all the way back to FragmentA.
Should I do the following:
on FragmentC call the method:
Navigation.findNavController(view).navigateUp();
then on FragmentB listen to some callback and using some passed parameter or argument trigger another navigateUp() function from FragmentB
or is there some method that will do the equivalent of navigateUpTwice()
What I ended up doing was
Navigation.findNavController(view).popBackStack(R.id.fragmant_a,false)
In your navigation.xml file under the action that you have created to navigate to starting fragment (FragmentA in your case) add the following
<action
....
app:popUpTo="#id/fragmentA"
app:popUpToInclusive="false"/>
This will pop up all the fragments until FragmentA and will exclude FragmentA since popUpToInclusive is set to false.
Edit:
The full form of your action under FragmentC tag of your navigation.xml file will be something similar to this:
<fragment
android:id="#+id/FragmentC"
android:name="com.yourdomain.FragmentC"
android:label="FragmentC">
<action
android:id="#+id/action_fragmentC_to_fragmentA"
app:destination="#id/fragmentA"
app:popUpTo="#id/fragmentA"
app:popUpToInclusive="false"/>
</fragment>
Try with this, it works for me.
findNavController().navigateUp()
findNavController().navigateUp()
You can set pop To FragmentA in your action from FragmentB --> FragmentC and when then you press back it goes to Fragment A instead of Fragment B
So I found myself in a situation where I had to navigateUp() twice, but with a twist: I could reach the view through several paths. Think of it like this:
Fragment A --> Fragment C --> Fragment D
Fragment B --> Fragment C --> Fragment D
In a normal situation, using the popTo xml attribute or the popBackStack() method would work. However it is unusable here. Fortunately, what you can do is:
val navController = NavHostFragment.findNavController(this)
navController.navigateUp()
navController.navigateUp
As other people have pointed out, this is absolutely not optimised performance-wise. In any situation where you can reach Fragment D through a single path, use popTo instead.