Navigation Component for Android Part 3: Transition and Navigation | raywenderlich.com

In this tutorial, you’ll learn how to use shared element transitions, action bar and bottom navigation to make an app that shows a list of random dogs images.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/8279305-navigation-component-for-android-part-3-transition-and-navigation

Can you navigate from one tab to another programmatically??

Hi!

Well, you can, but you’ll have to make some changes :].

Why it doesn’t work straight away

Each tab has its own independent nav graph. This means that you’ll have two independent NavHostFragment instances that know nothing about each other. In fact, if you try calling navController.navigate(R.id.favorites) somewhere in the Doggos tab’s screens, you’ll get a runtime exception saying that the destination is unknown.

What can you do about it

The solutions that come to mind are:

  • Nesting the graphs: By nesting one of the graphs into the other, the parent graph now knows how to navigate to the nested graph. Just know that this comes with the side effect of having the nested graph as part of the back stack of the parent graph. For example, if you nest the favorites graph in doggoList graph, you can now call navController.navigate(R.id.favorites) somewhere in the Doggos tab to navigate to the Favorites tab. However, if you press the back button, you’ll now end up in whatever screen of the Doggos tab you navigated from.

  • Using the bottom nav directly: you can access the BottomNavigationView directly and changing the selectedItemId to the screen you want to navigate to. For instance, if you trigger bottom_navigation.selectedItemId = R.id.favorites somewhere in MainActivity, you’ll navigate to the Favorites tab immediately, as the Navigation Component is already all wired up to respond to this change. The downside here is that by doing so, your navigation logic starts to become fragmented, as the Navigation Component is no longer responsible for everything directly.

Hope this answers your question. Let me know if you need anything else!

Hey!

Amazing tutorial! I’ve been studying the Navigation Component and this tutorial was eye opener for me.

I have some doubts though: let’s say I want to show a presenting/log-in screen before reaching the two tabbed screen.

  1. Will the BottomNavigationView still be part of the MainActivity? If so, should I hide it first thing?
  2. The presenting screen can have a “proceed” button. If I map it as a Navigation Action, should I link it to the first bottom navigation item (DoggoListFragment)? Is there a navigation-friendly way to notify the MainActivity so it can show the BottomNavigationView again?
  3. The presenting screen should show only in the first time the app is launched. Can I set the default startDestination programmatically then?

Thank you in advance!

Hello!

Thank you for your kind words. Much appreciated!

Answering your questions:

  1. If you want to keep a single Activity architecture, then yeah. You can set an OnDestinationChangedListener on the navController, which will let you take action depending on the destination. In this case, something like this should work:
navController.addOnDestinationChangedListener { _, destination, _ ->
   if(destination.id == R.id.loginFragment) {
       bottomNavigationView.visibility = View.GONE
   } else {
       bottomNavigationView.visibility = View.VISIBLE
   }
}
  1. You should link it to the first screen you want to be shown. If you want the Doggos tab to show first, then link it to DoggoListFragment. As for showing the bottom nav again, the above solution still holds.

  2. You can’t set the startDestination per se, but you can pop what’s in the back stack, thus effectively disabling navigation to previous screens. In order to do so, you need to use app:popUpTo and app:popUpToInclusive. These are used with navigation actions. app:popUpTo makes it so that the back stack is popped until it reaches whatever destination you pass as its parameter. As for app:popUpToInclusive, it tells the nav component to also pop the destination you pass as a parameter to app:popUpTo.
    That said, imagine that you want to navigate from the login screen to doggos list, and don’t want the user to be able to navigate back to the login screen. In that navigation action, you would have to do something like:

<fragment
        android:id="@+id/loginFragment"
        android:name="com.raywenderlich.android.mylittledoggo.presentation.login.LoginFragment"
        android:label="@string/login_fragment_label"
        tools:layout="@layout/fragment_login">

        <action
            android:id="@+id/to_doggoListFragment"
            app:destination="@id/DoggoListFragment"
            app:popUpTo="@id/LoginFragment"
            app:popUpToInclusive="true"/>
</fragment>

Hope this answers all your questions. Let me know if you need anything else and, again, thank you for your kind words!