Using global actions with multiple graphs in jetpack navigation

Viewed 4015

I created an application with a bottom navigation bar and added four different nav graphs using google's advanced navigation example

After that I added a fifth graph called settings that had the settings fragment along with a global action

I added an include to that graph on each of the first four graphs

when I do something like findNavController(R.id.container).navigate(SettingsDirections.showSettings()) the app crashes because it cannot find the destination or the action

but when I copy the fragment and the global action inside each of those graphs and call the above (with that graph's directions) it works

am I missing something? doesn't include actually copy everything from the other graph the original?

2 Answers

It seems that the include tag does not actually include all of the nav graph including the global actions

so in case someone wants to do something similar here is how I did it

first I updated the settings navigation to include a dummy action to show settings like so:

<?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/settings"
    app:startDestination="@+id/settings_dest">

    <include app:graph="@navigation/questions" />

    <!--this is just so safeargs will create a SettingsNavigation.showSettings it is never actually used-->
    <action
        android:id="@+id/show_settings"
        app:destination="@id/settings_dest" />

    <fragment
        android:id="@+id/settings_dest"
        android:name="com.example.app.ui.fragments.SettingsFragment"
        android:label="@string/settings"
        tools:layout="@layout/fragment_settings" >

        <argument
            app:argType="com.example.app.ui.model.SettingsProfile"
            android:name="profile"
            app:nullable="false"/>
    </fragment>
</navigation>

and then on every nav graph that I wanted to use the show_settings action I would do by including this:

<include app:graph="@navigation/settings" />

<action
    android:id="@+id/show_settings"
    app:destination="@id/settings"
    app:enterAnim="@anim/fade_in"
    app:exitAnim="@anim/fade_out"
    app:popEnterAnim="@anim/fade_in"
    app:popExitAnim="@anim/fade_out" />

so now when I want to use directions to go to settings I do it like this

findNavController().navigate(SettingsDirections.showSettings(profile))

this will use the directions created in my settings.xml to execute the action in my current nav controller

it is important by the way the id of the action in the included file and the id of the action of the file including it to be the same

I created an extension function when setting the default animation

fun View.navigate(id: Int, navOptions: NavOptions? = null){
  var updatedNavOptions = navOptions

  if(updatedNavOptions == null){
    updatedNavOptions = navOptions {
        anim {
            enter = R.anim.slide_in_right
            exit = R.anim.slide_out_left
            popEnter = R.anim.slide_in_left
            popExit = R.anim.slide_out_right
        }
    }
}

    this.findNavController().navigate(id, null, updatedNavOptions)
}

In my fragment just do so:

my_view.click { view?.navigate(R.id.how_referral_program_works) }
Related