I currently have this nav_graph.xml file.
Activity A (parent container), with this navigation tree:
Fragment A -> Fragment B -> Fragment C -> Fragment D -> Fragment E.
Also, I have an Activity B, and I want to navigate directly to Fragment C from this activity.
Does anyone know how I can realize an elegant solution for this case?
I have thought that I could launch an intent from Activity B -> Activity A passing it as an extra an enum corresponding to the desired fragment and that Activity A would handle the received parameter navigating through an action to the corresponding fragment. How do you see it? I think it can be improved and that's why I'm looking for a second solution. thanks!
Add this (your nav host fragment) in both of your activities with
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_view_pager_host"
android:layout_width="match_parent"
android:layout_height="670dp"
app:layout_constraintBottom_toTopOf="#+id/bottomNav"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/main_nav_graph"
app:defaultNavHost="true"/>
and then in your activity B onCreate() just add
val navController = (supportFragmentManager.findFragmentById(R.id.nav_view_pager_host) as NavHostFragment).navController
navController.navigate(/* To your fragment B*/)
//Handle anything else you wanna ddo
Related
I have a problem with setFragmentResultListener callback in my project. You can imagine that there is an activity with a fragment A on this. In fragment A, I set up a FragmentResultListener like this
setFragmentResultListener(AddImageDialogFragment::class.java.simpleName, this) { _, bundle -> }
and a button that clicking on it will open AddImageDialogFragment. This is code to open the dialog
AddImageDialogFragment.newInstance().show(parentFragmentManager, null)
In the dialog, I used this code to set result to Fragment A
setFragmentResult(this::class.java.simpleName, bundleOf())
The problem is that you can see in 2 case below
Case 1 (worked well)
Add fragment B to the activity that has already fragment A
Pop backstack to fragment A
Add open AddImageDialogFragment from fragment A and call
setFragmentResult -> the FragmentResultListener still worked well
Case 2 (not working)
Add fragment B to the activity that has already fragment A
Add fragment C to the activity that has already fragment A and B
Pop backstack to fragment C -> B -> A
Add open AddImageDialogFragment from fragment A and call
setFragmentResult -> the FragmentResultListener was not called
Does anyone know what happened to my code? I really appreciate your help!
I'm facing an issue concerning the use of navigation component.
I have this hierarchy :
Activity A composed of fragment f1 and fragment f2
Activity B
When I'm on f2, I change activity like this :
button.setOnClickListener {
startActivity(Intent(activityA, ActivityB::class.java))
}
What I would like is : When I go to activity B, the fragment f2 (of activity A) should be removed. So, when I will kill the activity B, I will come back to activity A without fragment f2.
To illustrate the flow :
Activity A (f1 > f2) > Activity B (Need to remove f2)
When I will come back : Activity B > Activity A (f1 only)
I'm using navigation component and I have tried to use the popUpTo and popUpToInclusive options in my nav_graph. I managed to remove the fragment but there is always a glitch when I remove it (i.e. we see the removal of fragment before passing the activity B, so we see the f1 fragment a little time). I would like to make the transaction invisible to user.
Is there a way to do it ? Don't hesistate to ask me if you need more precisions.
Thanks for your answers,
When you're using the navigation component, you can have direction, then use the navigation component to move from origin fragment/activity to destination fragment/activity. For example:
val actionLockToLogin = LockFragmentDirections.actionLockToLogin()
NavHost.findNavController(this).navigate(actionLockToLogin)
In this code, I go from LockFragment, to LoginFragment. Just add the fragments or activities in the navigation's XML. Set an Action from origin fragment / activity to destination fragment / activity. and by using the code I show you, try to navigate between them.
I have a Fragment A which navigates to Fragment B
Fragment B hosts a ViewPager2.
ViewPager2 has two fragments inflated in it - Fragment C and Fragment D.
On clicking an item in Fragment C I want to navigate to a new instance of Fragment D on top of Fragment B.
Currently, my code is something like this -
findNavController().navigate(
R.id.action_FragmentC_to_FragmentD,
bundleOf("id" to id, "type" to "list")
)
However, when I try to navigate I get the following exception -
java.lang.IllegalArgumentException: Navigation action/destination com.test.at:id/action_FragmentC_to_FragmentD cannot be found from the current destination Destination(com.krtkush.audiotime:id/FragmentB) label=FragmentB
From what I can understand is that the navigation component is still on Fragment B but I'm trying to navigate to Fragment D from Fragment C and hence it is throwing an exception.
I (think) can fix this by adding a listener which informs Fragment B when the item is tapped in Fragment C and then navigate to Fragment D from Fragment B. However, this will make my Fragment C tightly coupled to Fragment B which I don't want to. Anyway to fix this is another way?
If you do not navigate() to Fragment C and Fragment D, you will remain on the last destination you navigated to: Fragment B, that is the expected behavior. The NavController knows nothing about child fragments such as fragments within a ViewPager of Fragment B and therefore you were never on Fragment C as a destination.
If you never navigate() to Fragment C and it is only viewable as part of your ViewPager, then Fragment C should not be in your graph. Any actions from fragments within Fragment B's ViewPager should be actions on Fragment B directly (the destination you're actually on).
Note that you can reuse the same actions names on fragments such as Fragment D if you are also using them as standalone destinations in your graph (thus ensuring that the action is available in both cases).
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.
So I'm trying Jetpack navigation component with BottomNavigationView. I created two layer of BottomNavigationView, and the structure looks like this:
MainActivity (with nav_host_fragment, navigation_graph, bottom_navigation)
FragmentA
FragmentB
FragmentC (with nested_nav_host_fragment, nested_navigation_graph, nested_bottom_navigation)
FragmentCA
FragmentCB
FragmentCC
I have no problem navigating forward, but I couldn't navigate backward properly.
For example, when I navigation from A -> B -> C, and in C navigate CA -> CB -> CC, then clicking back button or calling navControler back, it should go from CC -> CB -> CA -> B -> A, but it straightly went to A instead.
The minimum demo project can be found here, hope someone can help, thanks.
By default, Fragments do not pop anything added to the back stack of child fragments.
To get the system back button to pop child Fragments of your Fragment C, you must specifically opt into that behavior by calling setPrimaryNavigationFragment().
This can be done anywhere in your Fragment after your Fragment is attached. For example, you can update your FragmentC to do it in onActivityCreated():
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
NavigationUI.setupWithNavController(nested_bottom_navigation,
activity?.findNavController(R.id.nested_nav_host_fragment)?:return)
// This routes the system back button to this Fragment
requireFragmentManager().beginTransaction()
.setPrimaryNavigationFragment(this)
.commit()
}
This is actually the same technique that the app:defaultNavHost="true" attribute on NavHostFragment is using under the hood.