Navigation Components conditional popUpTo? - android

Newbie on Navigation Component. I'm trying to achieve this but I don't know how:
I have 3 fragments:
FragmentA → FragmentList → FragmentAdd
If I try to go from FragmentMain to FragmentList but list is empty it should go directly to FragmentAdd (its not really directly since I'm checking the list on FragmentList but for the user it should look like it). If I'm on FragmentAdd and I go back (by either pressing back button or back on the toolbar) it should go back to FragmentMain (since FragmentList is still empty) but if I add something it should go back to FragmentList.
I've tried with
<fragment
android:id="#+id/fragmentMain" >
<action android:id="#+id/action_fragmentMain_to_fragmentList
app:destination="#id/fragmentList"
app:popUpTo="#id/fragmentMain"
app:popUpToInclusive="true"/>
</fragment>
The thing is that if I press back on FragmentAdd it will go to FragmentList, check that the list is still empty and go back to FragmentAdd. And if I pop FragmentList and then add something It will go to FragmentMain and not the list.
The difference with Conditional back navigation with Android Navigation Component is that I can add stuff to FragmentList from FragmentAdd
Any suggestion please?

Use app:popUpTo="#id/FragmentList" and app:popUpToInclusive="true" in action action_fragmentList_to_fragmentAdd
<fragment
android:id="#+id/fragmentMain" >
<action android:id="#+id/action_fragmentMain_to_fragmentList
app:destination="#id/fragmentList"/>
</fragment>
<fragment
android:id="#+id/fragmentList" >
<action android:id="#+id/action_fragmentList_to_fragmentAdd
app:destination="#id/fragmentAdd"
app:popUpTo="#id/fragmentList"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/fragmentAdd" >
</fragment>

Related

Navigation graph with viewpager2 android

My viewpager consists of 2 fragments which are displayed correctly and working fine.
From viewpager's fragment I want to move to another fragment via navigation graph
This is my graph
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/offer_nav_graph"
app:startDestination="#id/offersFragment">
<fragment
android:id="#+id/offersFragment"
android:name="com.octave.offers.OffersFragment"
android:label="offers_fragment"
tools:layout="#layout/offers_fragment" />
<fragment
android:id="#+id/availableOfferDetailFragment"
android:name="com.octave.offers.available.AvailableOfferDetailFragment"
android:label="fragment_available_offer_detail"
tools:layout="#layout/fragment_available_offer_detail" />
<fragment
android:id="#+id/availableOffersFragment"
android:name="com.octave.offers.available.AvailableOffersFragment"
android:label="fragment_available_offers"
tools:layout="#layout/fragment_available_offers" >
<action
android:id="#+id/action_availableOffersFragment_to_availableOfferDetailFragment"
app:destination="#id/availableOfferDetailFragment" >
<argument
android:name="offerId"
app:argType="integer"
android:defaultValue="-1" />
</action>
</fragment>
</navigation>
Offers fragment - has view pager
Available offer fragment - one of the fragment on view pager
Available offer detail fragment - i want to navigate
On button click I am calling this
AvailableOffersFragmentDirections.actionAvailableOffersFragmentToAvailableOfferDetailFragment(offerId)
The exception
Navigation action/destination com.octave.staging:id/action_availableOffersFragment_to_availableOfferDetailFragment cannot be found from the current destination Destination(com.octave.staging:id/homeFragment) label=HomeFragment class=com.octave.home.HomeFragment
What is wrong over here?
button exists on availableOffersFragment. I want to navigate from
availableOffersFragment to availableOfferDetailFragment.
offersFragment has the viewpager with 2 tabs having their own fragment
availableOffersFragment and secondFragemnt
So, now you need to navigate from availableOffersFragment which is a tab (page fragment) in the ViewPager; but this is not possible because those tabs don't affect the back stack. You can check out the questions discussed in here and also this one.
But what you can do instead is to add an action from offersFragment (which holds the ViewPager) to availableOfferDetailFragment as following:
Remove the tab fragments from the navGraph (availableOffersFragment and secondFragemnt).
Create an action in the navGraph from offersFragment to availableOfferDetailFragment
<fragment
android:id="#+id/offersFragment"
android:name="com.octave.offers.OffersFragment"
android:label="offers_fragment"
tools:layout="#layout/offers_fragment">
<action
android:id="#+id/action_offersFragment_to_availableOfferDetailFragment"
app:destination="#id/availableOfferDetailFragment" >
<argument
android:name="offerId"
app:argType="integer"
android:defaultValue="-1" />
</action>
</fragment>
When the button is clicked use parentFragment to access the offersFragment from the availableOffersFragment tab when the button is clicked. For instance:
Create a method in offersFragment:
goToDetailsFragment(offerId: Int) {
// perfrom the navaigation
OffersFragmentDirections.actionOffersFragmentToAvailableOfferDetailFragment(offerId)
}
And in availableOffersFragment
btn.setOnClickListener {
(parentFragment as offersFragment).goToDetailsFragment(offerId)
}
Check using:
btn.setOnClickListener {
Navigation.findNavController(it).navigate(R.id.availableOfferDetailFragment)
}

backstack does not clear while navigating from fragment to activity

Here is my code
<fragment
android:id="#+id/fragment1"
android:name="com.example.app.Fragment1"
android:label="SignatureFragment"
tools:layout="#layout/layout_fragment1">
<action
android:id="#+id/action_fragment1_to_main_activity"
app:destination="#id/main_activity"
app:enterAnim="#anim/slide_in_from_right"
app:exitAnim="#anim/no_anim"
app:launchSingleTop="true"
app:popEnterAnim="#anim/no_anim"
app:popExitAnim="#anim/slide_out_to_right"
app:popUpTo="#id/navigation_graph_id"
app:popUpToInclusive="true" />
</fragment>
<activity
android:id="#+id/main_activity"
android:name="com.example.app.MainActivity"
android:label="MainActivity"
tools:layout="#layout/activity_main" />
Now the code for navigation
findNavController().navigate(R.id.action_fragment1_to_main_activity)
When I navigate to activity and press back, the fragment is still there. I want to clear the backstack after opening the activity.
I tried to remove the animation and also tried with removing app:launchSingleTop, but no success.
Edit
Jetpack Navigation is intended to work with single activity and does not fully support activity navigation with parameters passed to actions
Thus to clear stack when navigating from one activity to another you will still need to call activity.finish()
Edit end
The thing is findNavController().navigate(R.id.action_fragment1_to_main_activity) wont work.
Try to navigate via navigate(#NonNull NavDirections directions). In your case it will look something like this
findNavController().navigate(
Fragment1Directions.actionFragment1ToMainActivity())
Hope it helps.

How can I go back directly to Fragment A since Fragment D without going back to Fragment C?

I use Android Navigation Architecture Component.
I have three Fragment A, B and C
Fragment A -> Fragment B -> Fragment D
Fragment A -> Fragment C -> Fragment D
On fragment D I have a button used to validate modifications and finish.
From this Frgament D I would like to:
return to Fragment B when I come from Fragment B (I use findNavController().navigateUp())
come back to Fragment A when I come from Fragment C (I don't know how to do it)
How can I go back directly to Fragment A when I come from Fragment D without going back to Fragment C?
Should I wait for the return on Fragment C and reprocess for the execution of findNavController().NavigateUp().
I use setPopUpTo on NavOptions, or you can use it inside the xml as well
documentation => https://developer.android.com/reference/androidx/navigation/NavOptions.Builder#setPopUpTo(int,%20boolean)
You can achieve both of these action with findNavController().NavigateUp()
Given the following graph for example:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/test_nav_graph"
app:startDestination="#id/a">
<fragment
android:id="#+id/a"
android:name="fragment.A"
tools:layout="#layout/a_fragment"
android:label="A" >
<action
android:id="#+id/action_a_to_b"
app:destination="#id/b" />
<action
android:id="#+id/action_a_to_c"
app:destination="#id/c" />
</fragment>
<fragment
android:id="#+id/b"
android:name="fragment.B"
tools:layout="#layout/b_fragment"
android:label="B" >
<action
android:id="#+id/action_b_to_d"
app:destination="#id/d" />
</fragment>
<fragment
android:id="#+id/c"
tools:layout="#layout/c_fragment"
android:name="fragment.C"
android:label="C" >
<action
android:id="#+id/action_c_to_d"
app:destination="#id/d"
app:popUpTo="#id/a"/>
</fragment>
<fragment
android:id="#+id/d"
tools:layout="#layout/d_fragment"
android:name="fragment.D"
android:label="D" />
</navigation>
When you take the path: A->B->D your back stack is A,B,D and when you call NavigateUp() you go back to B.
Now the path A->C->D has a minor addition in the action tag as you can see
<action
android:id="#+id/action_c_to_d"
app:destination="#id/d"
app:popUpTo="#id/a"/>
it has popUpTo, so when you navigate from C to D app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate(), so after navigating to D your back stack is A,D and NavigateUp() takes you back to A
So when you are in Fragment D and pressing back button . You can check the fragment stack and check for example
onBackPress(){
childFragmentManager.popbackstack()
val currentFragment = findFragmentByTag("FRAGMENT_B")
if(currentFragment == childFragmentManager.primaryNavigation()){
childFragmentManager.popbackstack()
}
NOTE
Above snippet is written without editor. You can use this logic.

Is it possible to start with a "non-start" fragment using Android Navigation Architecture Component(Android Jetpack)?

so I have the following navigation graph:
Fragment A (start) --> Fragment B
So for some situations (firebase notifications), I need to start Fragment B directly, passing data from the notifications. Now, this works. However, when I press the back button, it results in a crash. Is it because the leading fragment (Fragment A) is not in the stack? If so, is there a way to properly handle this.
Basically, I need the backPressed action to launch the start Fragment (Fragment A) in a situation where Fragment B is launched directly without passing through Fragment A.
Below is a snippet of my graph:
<fragment
android:id="#+id/homeFragment"
android:name="dita.dev.myportal.ui.home.HomeFragment"
android:label="Home"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/action_homeFragment_to_messageDetailFragment"
app:destination="#id/messageDetailFragment"
app:exitAnim="#anim/fade_out_animation" />
</fragment>
<fragment
android:id="#+id/messageDetailFragment"
android:name="dita.dev.myportal.ui.messages.details.MessageDetailFragment"
android:label="Message"
tools:layout="#layout/fragment_message_detail">
<argument
android:name="title"
app:argType="string" />
<argument
android:name="message"
app:argType="string" />
</fragment>
I hope the link helps.
https://developer.android.com/guide/navigation/navigation-deep-link
Deep links allow for synthetic back-stacks.
Quoted from the website, "This means that when a user presses the Back button from a deep link destination, they navigate back up the navigation stack just as though they entered your app from its entry point."
Maybe trying to create a deep link for Fragment B will work.

Android NavigationUI - Handle backpress when starting fragment is poped out

I am using NavigationUI of android architecture components with bottom navigation in my android app. I have the following situation
The app starts at Fragment A
Initial calculation is done and now I pop out Fragment A by navController.popBackStack()
The app goes to Fragment B (This serves as a 'Home' for the app)
Now there are more fragments say C and D
The user can navigate between B, C and D
Now the problem is in my navigation graph, my starting fragment was A (by defining app:startDestination="#id/fragmentA") but that is now pop out of the activity. Due to this, anytime if I backpress, the app just closes instead going back to the previous fragment. For example, let's say I navigate to Fragment C or D from fragment B and if I press back button, my app will close instead of going to fragment B. If the there way to 'reassign' the startDestination?
I checked the answer to this question which has a similar situation as above but using NavOptions is somehow not working. Is there any other way? Following is the code I used to pop fragment and add nav options
navController.popBackStack()
val navOptions: NavOptions = NavOptions.Builder()
.setPopUpTo(R.id.homeFragment, true)
.build()
navController.navigate(R.id.action_fragmentA_to_fragmentB, null, navOptions)
Use this navigation graph. Hope it will solve your problem.
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/nav_graph"
app:startDestination="#id/fragment_a">
<fragment
android:id="#+id/fragment_a"
tools:layout="#layout/fragment_a">
<action
android:id="#+id/action_a_to_b"
app:destination="#id/fragment_b"
app:popUpTo="#id/fragment_a"
app:popUpToInclusive="true"/>
</fragment>
<fragment
android:id="#+id/fragment_b"
tools:layout="#layout/fragment_b">
<action
android:id="#+id/action_b_to_c"
app:destination="#id/fragment_c"/>
</fragment>
<fragment
android:id="#+id/fragment_c"
tools:layout="#layout/fragment_c">
</fragment>
</navigation>
Use the following line for navigation:
navController.navigate(R.id.action_a_to_b)
navController.navigate(R.id.action_b_to_c)

Categories

Resources