导航组件不弹出片段
Navigation component doesn't pop fragment
当我们打开应用程序时,我会显示一个介绍片段。一段时间后,在介绍片段中,我将用户导航到提要片段。当用户按下后退按钮时,在提要片段上,我需要显示一个退出对话框。当用户点击退出时,我需要关闭应用程序。
这是我的导航图。
<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/fragment_intro">
<fragment
android:id="@+id/fragment_feed"
android:name="FeedFragment"
tools:layout="@layout/fragment_feed"/>
<fragment
android:id="@+id/fragment_intro"
android:name="IntroFragment"
tools:layout="@layout/fragment_intro">
<action
android:id="@+id/action_introFragment_to_feedFragment"
app:destination="@id/fragment_feed"
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/mobile_navigation"
app:popUpToInclusive="true" />
</fragment>
</navigation>
就是这样。我的起始目的地是 Intro 片段。我有一个操作,可以将我导航到提要片段。当我导航到提要片段时,我会弹出我的介绍片段。
关于代码,在介绍片段中,我在 3 秒后导航到提要片段。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Handler(Looper.getMainLooper()).postDelayed({
val action = IntroFragmentDirections.actionIntroFragmentToFeedFragment()
findNavController().navigate(action)
}, 3000)
}
所以在提要片段中,当用户单击后退按钮时,我需要显示一个退出对话框。这意味着,我需要抓住后压,这是我用这种方式完成的。
在我的提要片段的 onCreateView() 中,我添加了这个
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Show exit dialog
}
}
)
当用户点击后退按钮时,我简单地调用了这个函数
fun onExit() {
findNavController().navigateUp()
}
但是当我单击退出按钮时,它 returns 返回到我弹出的介绍片段。那么为什么它没有弹出,我做错了什么?
---编辑---
一种解决方案是删除 dispatcherCallback
并调用 onBackPressed()
,但我认为这不是一个好方法。
val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Show exit dialog
}
}
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner, onBackPressedCallback
)
fun onExit() {
onBackPressedCallback.remove()
activity?.onBackPressed()
}
谢谢。
一段时间后我找到了解决方案,也许这会对某人有所帮助。所以片段没有弹出的问题是,因为当我们的 backstack
中只有一个片段时,或者我们尝试弹出我们的起始目标片段时,navigateUp()
函数将 return false片段不会被弹出。那为什么会这样呢?因为 navigateUp
导航到导航主机中的上一个片段。但是如果没有片段,我们的导航控制器可以导航到哪里,它只是 returns false。所以我们需要一个函数来确定这是否是我们图中唯一的片段,我们不能向上导航也可以。因为每次都调用 activity?.onBackPressed()
不是一个好的解决方案。所以为了实现这一点,我们可以创建一个这样的扩展函数:
fun NavController.navigateUpOrFinish(activity: FragmentActivity): Boolean {
return if (navigateUp()) {
true
} else {
activity.finish()
true
}
}
就是这样。现在我们可以在对话框退出时调用这个函数 click
fun onExit() {
findNavController().navigateUpOrFinish(requireActivity())
}
如果有一个片段,我们可以在其中导航,它会调用 navigateUp()
在其他情况下,它只会调用 backPressed 并且我们的应用程序将关闭。谢谢。
当我们打开应用程序时,我会显示一个介绍片段。一段时间后,在介绍片段中,我将用户导航到提要片段。当用户按下后退按钮时,在提要片段上,我需要显示一个退出对话框。当用户点击退出时,我需要关闭应用程序。
这是我的导航图。
<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/fragment_intro">
<fragment
android:id="@+id/fragment_feed"
android:name="FeedFragment"
tools:layout="@layout/fragment_feed"/>
<fragment
android:id="@+id/fragment_intro"
android:name="IntroFragment"
tools:layout="@layout/fragment_intro">
<action
android:id="@+id/action_introFragment_to_feedFragment"
app:destination="@id/fragment_feed"
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/mobile_navigation"
app:popUpToInclusive="true" />
</fragment>
</navigation>
就是这样。我的起始目的地是 Intro 片段。我有一个操作,可以将我导航到提要片段。当我导航到提要片段时,我会弹出我的介绍片段。
关于代码,在介绍片段中,我在 3 秒后导航到提要片段。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Handler(Looper.getMainLooper()).postDelayed({
val action = IntroFragmentDirections.actionIntroFragmentToFeedFragment()
findNavController().navigate(action)
}, 3000)
}
所以在提要片段中,当用户单击后退按钮时,我需要显示一个退出对话框。这意味着,我需要抓住后压,这是我用这种方式完成的。 在我的提要片段的 onCreateView() 中,我添加了这个
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Show exit dialog
}
}
)
当用户点击后退按钮时,我简单地调用了这个函数
fun onExit() {
findNavController().navigateUp()
}
但是当我单击退出按钮时,它 returns 返回到我弹出的介绍片段。那么为什么它没有弹出,我做错了什么?
---编辑---
一种解决方案是删除 dispatcherCallback
并调用 onBackPressed()
,但我认为这不是一个好方法。
val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Show exit dialog
}
}
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner, onBackPressedCallback
)
fun onExit() {
onBackPressedCallback.remove()
activity?.onBackPressed()
}
谢谢。
一段时间后我找到了解决方案,也许这会对某人有所帮助。所以片段没有弹出的问题是,因为当我们的 backstack
中只有一个片段时,或者我们尝试弹出我们的起始目标片段时,navigateUp()
函数将 return false片段不会被弹出。那为什么会这样呢?因为 navigateUp
导航到导航主机中的上一个片段。但是如果没有片段,我们的导航控制器可以导航到哪里,它只是 returns false。所以我们需要一个函数来确定这是否是我们图中唯一的片段,我们不能向上导航也可以。因为每次都调用 activity?.onBackPressed()
不是一个好的解决方案。所以为了实现这一点,我们可以创建一个这样的扩展函数:
fun NavController.navigateUpOrFinish(activity: FragmentActivity): Boolean {
return if (navigateUp()) {
true
} else {
activity.finish()
true
}
}
就是这样。现在我们可以在对话框退出时调用这个函数 click
fun onExit() {
findNavController().navigateUpOrFinish(requireActivity())
}
如果有一个片段,我们可以在其中导航,它会调用 navigateUp()
在其他情况下,它只会调用 backPressed 并且我们的应用程序将关闭。谢谢。