如何在片段导航组件中仅从后堆栈中移除一个片段?

20

在我的应用程序中,我使用了一个Activity和四个Fragment。在这个应用程序中,我使用了Navigation组件。我的Fragment加载顺序是A->B->C->D。

在Fragment D中,当设备的返回按钮按下时,我想从后退栈中移除Fragment C,以便可以打开Fragment B。请问有什么建议或方法可以实现吗?谢谢!

这是我的navigation_graph.xml文件。

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

    app:startDestination="@id/firstFragment"
    >
    <fragment
        android:id="@+id/firstFragment"
        android:name="com.education.javaprogramming.fragments.MainFragment"
        android:label="fragment_first"
        tools:layout="@layout/activity_main" >

        <action
            android:id="@+id/action_firstFragment_to_displayList1Fragment"
            app:destination="@id/displayList1Fragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"
            />
        <action
            android:id="@+id/action_firstFragment_to_displayList2Fragment"
            app:destination="@id/displayList2Fragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
        <action
            android:id="@+id/action_firstFragment_to_helpFragment"
            app:destination="@id/helpFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"
            />
        <action
            android:id="@+id/action_firstFragment_to_quizzFragment"
            app:destination="@id/quizzFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
    </fragment>
    <fragment
        android:id="@+id/displayList1Fragment"
        android:name="com.education.javaprogramming.fragments.DisplayList1Fragment"
        android:label="fragment_display_list1"
        tools:layout="@layout/fragment_display_list1"

        >
        <argument
            android:name="position1"
            app:argType="integer" />
        <action
            android:id="@+id/action_displayList1Fragment_to_firstFragment"
            app:destination="@id/firstFragment" />
        <argument
            android:name="name"
            app:argType="string" />
        <action
            android:id="@+id/action_displayList1Fragment_to_displayList2Fragment"
            app:destination="@id/displayList2Fragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"


            />
    </fragment>
    <fragment
        android:id="@+id/displayList2Fragment"
        android:name="com.education.javaprogramming.fragments.DisplayList2Fragment"
        android:label="fragment_display_list2"
        tools:layout="@layout/fragment_display_list2" >
        <action
            android:id="@+id/action_displayList2Fragment_to_displayList1Fragment"
            app:destination="@id/displayList1Fragment"

            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"
            />
        <action
            android:id="@+id/action_displayList2Fragment_to_firstFragment"
            app:destination="@id/firstFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
        <argument
            android:name="position1"
            app:argType="integer" />
        <argument
            android:name="position2"
            app:argType="integer" />
        <argument
            android:name="name"
            app:argType="string" />
        <action
            android:id="@+id/action_displayList2Fragment_to_displayListInDeFragment"
            app:destination="@id/displayListInDeFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
    </fragment>
    <fragment
        android:id="@+id/displayListInDeFragment"
        android:name="com.education.javaprogramming.fragments.DisplayListInDeFragment"
        android:label="fragment_display_list_in_de"
        tools:layout="@layout/fragment_display_list_in_de" >
        <action
            android:id="@+id/action_displayListInDeFragment_to_displayList2Fragment"
            app:destination="@id/displayList2Fragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
        <argument
            android:name="position1"
            app:argType="integer" />
        <argument
            android:name="position2"
            app:argType="integer" />
        <argument
            android:name="position3"
            app:argType="integer" />
        <argument
            android:name="name"
            app:argType="string" />
    </fragment>
    <fragment
        android:id="@+id/helpFragment"
        android:name="com.education.javaprogramming.fragments.HelpFragment"
        android:label="fragment_help"
        tools:layout="@layout/fragment_help" >
        <action
            android:id="@+id/action_helpFragment_to_firstFragment"
            app:destination="@id/firstFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"
            />
        <argument
            android:name="position1"
            app:argType="integer" />
        <argument
            android:name="name"
            app:argType="string" />
        <action
            android:id="@+id/action_helpFragment_to_aboutFragment"
            app:destination="@id/aboutFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
    </fragment>
    <fragment
        android:id="@+id/aboutFragment"
        android:name="com.education.javaprogramming.fragments.AboutFragment"
        android:label="fragment_about"
        tools:layout="@layout/fragment_about" >
        <action
            android:id="@+id/action_aboutFragment_to_helpFragment"
            app:destination="@id/helpFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"
            />
    </fragment>
    <fragment
        android:id="@+id/quizzFragment"
        android:name="com.education.javaprogramming.fragments.QuizzFragment"
        android:label="fragment_quizz"
        tools:layout="@layout/fragment_quizz" >
        <action
            android:id="@+id/action_quizzFragment_to_firstFragment"
            app:destination="@id/firstFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
        <action
            android:id="@+id/action_quizzFragment_to_displayExamFragment"
            app:destination="@id/displayExamFragment" />
    </fragment>
    <fragment
        android:id="@+id/displayExamFragment"
        android:name="com.education.javaprogramming.fragments.DisplayExamFragment"
        android:label="fragment_display_exam"
        tools:layout="@layout/fragment_display_exam" >
        <action
            android:id="@+id/action_displayExamFragment_to_quizzFragment"
            app:destination="@id/quizzFragment"
            app:enterAnim="@anim/enter"
            app:exitAnim="@anim/exit"
            app:popEnterAnim="@anim/pop_enter"
            app:popExitAnim="@anim/pop_exit"

            />
        <argument
            android:name="position1"
            app:argType="integer" />
        <action
            android:id="@+id/action_displayExamFragment_to_resultFragment"
            app:destination="@id/resultFragment" />
    </fragment>
    <fragment
        android:id="@+id/resultFragment"
        android:name="com.education.javaprogramming.fragments.ResultFragment"
        android:label="fragment_result"
        tools:layout="@layout/fragment_result" >
        <action

            android:id="@+id/action_resultFragment_to_quizzFragment"
            app:destination="@id/quizzFragment" />
        <argument android:name="givenAnswers"
            app:argType="reference"
            />
        <argument android:name="actualAnswers"
            app:argType="reference"
            />
    </fragment>


</navigation>

你想用一个后退点击删除D和C片段吗? - Mohit Kalia
你需要使用tags和popBackstack来弹出特定的fragment并删除其他的。请参考https://dev59.com/plkT5IYBdhLWcg3wRNUR#38853275。 - Anis BEN NSIR
是的。当我在片段D上并按下返回按钮时,我想要移除C和D。 - Sushant Bansode
@SushantBansode,你能提供你的nav_graph.xml吗? - Anis BEN NSIR
你可以在这里查看我的答案。 - George Samuel
显示剩余3条评论
6个回答

13

我遇到了几乎相同的问题,这个解决方案帮助了我!感谢@bharatesh - Augusto Pinto

10

你应该使用

      app:popUpTo="@id/id_of_c_fragment" 
      app:popUpToInclusive="true"
      app:popUpTo="@id/id_of_d_fragment"
      app:popUpToInclusive="true"

在导航图中的操作范围内。


3
对我来说完全符合我的需求,而且我认为这样做比编程更简单,将其放在xml中。 - FabioR

3
在Fragment D中,如果你想返回到Fragment B(移除Fragment C),你可以使用以下代码:
Navigation.findNavController(requireView()).popBackStack(
    R.id.id_of_fragment_C, true)

id_of_fragment_C 是您想要跳过的片段的ID。


1

我曾经也遇到过同样的问题,但是我是这样解决的

    <action
        android:id="@+id/id_action"
        app:destination="@id/fragment_D"
        app:launchSingleTop="true"
        app:popUpTo="@id/fragment_B"
        app:popUpToInclusive="true" />

0

如果您知道要返回的目标位置,我建议您使用@Bharatesh的答案;

或者如果您更喜欢XML方式,则可以使用@sudo007的答案。

如果您不知道用户从哪里导航到当前屏幕,因为有多条路径到达当前目标,请尝试以下方法:

button.setOnClickListener {
        val navController= it.findNavController()
        navController.previousBackStackEntry?.let { backEntry -> navController.popBackStack(backEntry.destination.id,true) }
    }

这将动态检索您先前的后退堆栈条目,并从后退堆栈中弹出当前和先前的目标。

true 在此处使其包括要从 backStack 弹出的编写目标。

如果 lambda 表达式难以理解,请尝试下面的代码:

val navController = it.findNavController()
    val prevId = navController.previousBackStackEntry?.destination?.id
    if (prevId != null) {
        navController.popBackStack(prevId, true)
    }

0

我需要一个类似的场景,其中一个用户在验证屏幕(A)上必须通过指令屏幕(B)和上传屏幕(C)。

这里是所需的导航旅程

  • 前向导航 A > B > C
  • 后向导航 A < C
  • 在片段C成功上传后的导航 A < C

因此,为了实现这一点,这里是我必须编写的导航操作。

要导航 A > B,只需简单导航
<action
android:id="@+id/action_verification_to_upload_info"
app:destination="@id/navigation_upload_info" />
导航至 B > C

弹出回退至包括 B 的位置,最终着陆在 A。

<action android:id="@+id/action_id_upload_info_to_verification_upload"
app:popUpTo="@id/action_verification_to_upload_info"
app:popUpToInclusive="true"
app:destination="@id/navigation_id_verification_upload" />

请注意,app:popUpTo 的值为 Fragment B 的 navID,且 app:popUpToInclusive="true"
这对我非常有效!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接