简体   繁体   中英

How to switch to other fragment in different back stack using Navigation Component?

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?

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)
    }
}

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"))

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" />

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM