10

I have 3 bottom navigation tabs called Home, Dashboard, Profile.

  • In Home, I have Fragment1 and Fragment2,
  • In Dashboard, I have Fragment3 and Fragment4
  • And in Profile, I have MyProfile and EditProfile.

Now, in Fragment2, a button changeAvatar can open EditProfile in stack Profile. Because EditProfile should be in tab Profile, so if I don't want to include EditProfile into navGraph of Home, how can I achieve that behavior?

NamNH
  • 1,752
  • 1
  • 15
  • 37
  • I could not understand, you want fragment 6 to load, in navigation A or C? – hemen Apr 29 '20 at 09:25
  • @notTdar sorry, I edited for more readable. – NamNH Apr 29 '20 at 10:24
  • Do you have 3 nav_graphs? Why not using 1 Activity with 1 nav_graph which has all 6 fragments as possible destinations? – muetzenflo May 02 '20 at 21:52
  • @muetzenflo yes, exactly using 3 nav_graphs with same as [`NavigationAdvanceSample`](https://github.com/android/architecture-components-samples/tree/master/NavigationAdvancedSample) . How can I use 1 nav_graph if I use `BottomNavigationView` ? each stack should keep its top fragment when I came back. – NamNH May 03 '20 at 14:19
  • ah, i see. Didnt get this requirement. Sorry, another question: Why do you not want to use EditProfile in the Home-nav_graph. If you use the ViewModel approach from Jetpack, it should be no problem to use EditProfile as "third" navigation destination in `Home`. You can use 1 nav_graph, if the BottomNavigation is part of the activity which holds the navHostFragment. – muetzenflo May 03 '20 at 17:19
  • No, you can't use 1 nav_graph because only the top fragment in a back stack is kept, all other fragment will be destroyed (view) state. Suppose from `Home`, I go to `Fragment1, 2` (or deeper like go to detail, detail...), switch to tab `Dashboard`, I go to `Fragment3,4,5`... then I select the `Home` tab, `Fragment2` must be shown . – NamNH May 04 '20 at 08:22

4 Answers4

5

What you are looking for is known as global action.

Given you have the following nav_graph structure:

<?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/main_nav_graph"
            app:startDestination="@id/actionHome">

    <navigation
            android:id="@+id/actionHome"
            android:label="Home"
            app:startDestination="@id/fragment1">
        <fragment
                android:id="@+id/fragment1"
                android:name="com.example.app.Fragment1"
                android:label="Home Fragment 1"
                tools:layout="@layout/fragment_1" />
        <fragment
                android:id="@+id/fragment2"
                android:name="com.example.app.Fragment2"
                android:label="Home Fragment 2"
                tools:layout="@layout/fragment_2" />

    </navigation>

    <navigation
            android:id="@+id/actionDashboard"
            android:label="Dashboard"
            app:startDestination="@id/fragment3">
        <fragment
                android:id="@+id/fragment3"
                android:name="com.example.app.Fragment3"
                android:label="Dashboard Fragment 3"
                tools:layout="@layout/fragment_3" />
        <fragment
                android:id="@+id/fragment4"
                android:name="com.example.app.Fragment4"
                android:label="Dashboard Fragment 4"
                tools:layout="@layout/fragment_4" />

    </navigation>

    <navigation
            android:id="@+id/actionProfile"
            android:label="Profile"
            app:startDestination="@id/myProfileFragment">
        <fragment
                android:id="@+id/myProfileFragment"
                android:name="com.example.app.MyProfileFragment"
                android:label="My Profile"
                tools:layout="@layout/fragment_my_profile"/>

        <fragment
                android:id="@+id/editProfileFragment"
                android:name="com.example.app.EditProfileFragment"
                android:label="Edit Profile"
                tools:layout="@layout/fragment_edit_profile"/>

        <action
                android:id="@+id/navigateToEditProfile"
                app:destination="@id/editProfileFragment" />
    </navigation>
</navigation>

Note the action section within actionProfile:

<action
        android:id="@+id/navigateToEditProfile"
        app:destination="@id/editProfileFragment" />

The above is the actual global action that you are looking for.

So to put the flow into perspective you would do the following to navigate from Fragment2 changeAvatar button.

fun navigateToChangeAvatar() {
    changeAvatar.setOnClickListener { view ->
        view.findNavController().navigate(R.id.navigateToEditProfile)
    }
}
Rodrigo Queiroz
  • 2,674
  • 24
  • 30
4

try with the deep link

Navigation graph.

<navigation
 ...>
    <fragment
        android:id="@+id/editProfileFragment"
        >

        ...
        <deepLink
            android:id="@+id/deepLink"
            app:uri="yourapp://edit/prfile" />
        ...
    </fragment>
</navigation>

In Fragment.

findNavController().navigate(Uri.parse("yourapp://edit/prfile"))
  • Have you try this, what's happened with the stacks? Can you share more with this solution? – NamNH May 07 '20 at 02:44
2

You have to declare your action like this for getting a fragment from your back stack

<action
    android:id="@+id/yourActionName"
                 app:destination="@id/editProfileFragment" />
                 app:enterAnim="@anim/slide_in_right"
                 app:exitAnim="@anim/slide_out_left"
                 app:popEnterAnim="@anim/slide_in_left"
                 app:popExitAnim="@anim/slide_out_right"
                 app:popUpTo="@+id/editProfileFragment" />
2

To navigate from Home > Fragment2 to Profile > EditProfile you can pass an id by edit type using Navigation.

Fragment2.kt

private fun navigateToEditProfileAvatar() {
    buttonEditProfileAvatar.setOnClickListener { button -> 
        Navigation.findNavController(button).navigate(
                R.id.action_global_to_edit_profile,
                RootNavigationDirections.actionGlobalToEditProfile(
                        editType = EditType.EDIT_PROFILE_AVATAR.id
                ).arguments
        )
    }
}

EditProfileFragment.kt

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState) 

    ...

    viewModel.setEditTypeId(EditProfileFragmentArgs.fromBundle(arguments ?: Bundle()).editType)

}

private fun bind() {
    when (viewModel.editTypeId) {
         EditType.EDIT_PROFILE.id -> { ... }
         EditType.EDIT_PROFILE_AVATAR.id -> { 
             // here
         }
    }
}

EditProfileVM.kt

val editTypeId = MutableLiveData<String>()
fun setEditTypeId(id: editTypeId ) {...}

res/navigation/root_navigation.xml

<action
    android:id="@+id/action_global_to_edit_profile"
    app:destination="@id/edit_profile_fragment" />

<fragment
    android:id="@+id/edit_profile_fragment"
    android:name="EditProfileFragment"
    android:label=" "
    tools:layout="@layout/fragment_edit_profile">

    <argument
        android:name="editType"
        app:argType="string"
        android:defaultValue="@string/edit_profile"
    />

</fragment>

EditType.kt

enum class EditType(val id: String) {
    EDIT_PROFILE("EDIT_PROFILE"), EDIT_PROFILE_AVATAR("EDIT_PROFILE_AVATAR");
}

Note: The arguments of a navigation cannot be of type Enum

GL

Braian Coronel
  • 22,105
  • 4
  • 57
  • 62