如何将 android 导航 backstack 弹出到某个片段?
Posted
技术标签:
【中文标题】如何将 android 导航 backstack 弹出到某个片段?【英文标题】:How do I pop android navigation backstack up to a certain fragment? 【发布时间】:2021-05-16 05:30:31 【问题描述】:我再次请求您的智力支持。
我有一个片段,它把自己的多个副本放在导航堆栈上,如下所示:
Navigation.findNavController(button).navigate(
TaskCollectFragmentDirections.actionTaskCollectFragmentSelf(args.taskIndex, args.screenIndex + 1)
)
上面的代码按预期工作。
问题来了,当我想从导航堆栈中弹出指定数量的这些片段时。 (由按下按钮触发。)
我试过这样做:
Navigation.findNavController(button).popBackStack(lastRecurringFragmentId, false)
我的代码编译并运行,但什么也不做。当我没有给popBackStack
函数提供任何参数时,它会正确地弹出最上面的片段。我还可以使用后退箭头一直导航到起始片段。
如果它很重要,lastRecurringFragmentId
来自这个函数:
fun getLastRecurringFragmentId(recurringFragmentCount: Int): Int
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)!!
val backStackEntryCount = navHostFragment.childFragmentManager.backStackEntryCount
val indexOfRequested = backStackEntryCount - recurringFragmentCount
val requestedEntry = navHostFragment.childFragmentManager.getBackStackEntryAt(indexOfRequested)
return requestedEntry.id
导航图如下。应该有几个 TaskCollectFragment
s 和最后一个 TaskEndFragment
在 backstack 的顶部。当用户按下TaskEndFragment
上的按钮时,我想将一些TaskCollectFragment
s 从堆栈中弹出:
<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/mobile_navigation"
app:startDestination="@id/nav_home">
<fragment
android:id="@+id/nav_home"
android:name="ui.home.HomeFragment"
android:label="@string/menu_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_nav_home_to_taskCollectFragment"
app:destination="@id/taskCollectFragment" />
</fragment>
<fragment
android:id="@+id/taskCollectFragment"
android:label="TaskCollectFragment"
tools:layout="@layout/task_collect_fragment"
>
<action
android:id="@+id/action_taskCollectFragment_to_taskEndFragment"
app:destination="@id/taskEndFragment" />
<action
android:id="@+id/action_taskCollectFragment_self"
app:destination="@id/taskCollectFragment" />
<argument
android:name="taskIndex"
app:argType="integer" />
<argument
android:name="screenIndex"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/taskEndFragment"
android:name="ui.task.TaskEndFragment"
android:label="TaskEndFragment"
tools:layout="@layout/task_end_fragment">
<argument
android:name="taskIndex"
app:argType="integer" />
</fragment>
</navigation>
有没有办法可以在满足特定条件之前从后台弹出片段?
【问题讨论】:
您的getLastRecurringFragmentId()
在使用导航时没有任何意义 - 您传递给 popBackStack()
的 ID 是导航图中的 android:id
s。你能包括你的导航图吗?
@ianhanniballake 这是否意味着我无法区分片段的多个实例?
如果你说在pop之后你希望你的堆栈是什么会更好?您是否希望弹出所有 taskCollectFragment
实例,而只有 nav_home
仍在堆栈中?
@ianhanniballake 正如我所说,我想弹出一些taskCollectFragment
s。可能只是少数,也可能是全部,视情况而定。感谢您让我知道 ID 的来源,它给了我一个想法!
【参考方案1】:
我创建了两个几乎相同的片段,forSessionTaskCollectFragment
和 recurringTaskCollectFragment
具有相同的 viewModel。它们看起来是一样的,从用户的角度来看它们也是一样的。
forSessionTaskCollectFragment
s 是我想要保留的,recurringTaskCollectFragment
s 是我想稍后弹出的。
从主页片段,我的导航图转到forSessionTaskCollectFragment
,从那里它循环回到自己或转到recurringTaskCollectFragment
,它也循环回到自己或最终转到TaskEndFragment
<fragment
android:id="@+id/nav_home"
android:name="ui.home.HomeFragment"
android:label="@string/menu_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_nav_home_to_orSessionTaskCollectFragment"
app:destination="@id/forSessionTaskCollectFragment" />
</fragment>
<fragment
android:id="@+id/forSessionTaskCollectFragment"
android:name="ui.task.ForSessionTaskCollectFragment"
android:label="ForSessionTaskCollectFragment" >
<action
android:id="@+id/action_forSessionTaskCollectFragment_self"
app:destination="@id/forSessionTaskCollectFragment" />
<action
android:id="@+id/action_forSessionTaskCollectFragment_to_recurringTaskCollectFragment"
app:destination="@id/recurringTaskCollectFragment" />
<argument
android:name="taskIndex"
app:argType="integer" />
<argument
android:name="screenIndex"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/recurringTaskCollectFragment"
android:name="ui.task.RecurringTaskCollectFragment"
android:label="TaskCollectFragment"
tools:layout="@layout/recurring_task_collect_fragment"
>
<action
android:id="@+id/action_recurringTaskCollectFragment_to_taskEndFragment"
app:destination="@id/taskEndFragment" />
<action
android:id="@+id/action_recurringTaskCollectFragment_self"
app:destination="@id/recurringTaskCollectFragment" />
<argument
android:name="taskIndex"
app:argType="integer" />
<argument
android:name="screenIndex"
app:argType="integer" />
</fragment>
我将forSessionTaskCollectFragment
s 放在堆栈上,直到我到达我想要返回的位置。
Navigation.findNavController(button).navigate(
if(args.screenIndex < viewModel.forSessionScreenCount)
ForSessionTaskCollectFragmentDirections.actionForSessionTaskCollectFragmentSelf(args.taskIndex, args.screenIndex + 1)
else
ForSessionTaskCollectFragmentDirections.actionForSessionTaskCollectFragmentToRecurringTaskCollectFragment(args.taskIndex, args.screenIndex + 1)
)
之后我把后面要弹回来的片段放回去,最后到TaskEndFragment
,从那里我要弹我需要的片段:
Navigation.findNavController(button).navigate(
if(args.screenIndex < viewModel.screenCount - 2)
RecurringTaskCollectFragmentDirections.actionRecurringTaskCollectFragmentSelf(args.taskIndex, args.screenIndex + 1)
else
RecurringTaskCollectFragmentDirections.actionRecurringTaskCollectFragmentToTaskEndFragment(args.taskIndex)
)
因此,在TaskEndFragment
的按钮按下时,我可以弹回后台堆栈上我标记为从“会话”片段更改为“重复”片段的确切位置:
Navigation.findNavController(button).popBackStack(R.id.forSessionTaskCollectFragment, false)
这很麻烦,我没有找到任何我想做的事情的例子,但最终设法想出了一个可行的解决方案。 Ianhanniballake 再次感谢,你激发了我的想法。
【讨论】:
你好哦/。这不是你问的问题的答案。您实际上不是回到某个片段,而是向前导航。 有什么解释吗?它按预期工作。我建议你仔细阅读全文。我在添加片段时向前导航。诀窍是在我想要返回的地方更改我添加的框架类型。然后,当我需要后退时,我可以通过调用“Navigation.findNavController(button).popBackStack(R.id.forSessionTaskCollectFragment, false)”来实现,我很确定我不会通过这样做向前导航。以上是关于如何将 android 导航 backstack 弹出到某个片段?的主要内容,如果未能解决你的问题,请参考以下文章
当backstack为空时,按下android上的后退按钮会破坏导航逻辑
android-clearing backstack 生成 NullPointerException
使用单独的 backstack 创建类似底部导航的 Instagram
导航抽屉backstack,如何让actionbar标题在点击后随片段改变