导航组件不会弹出片段

时间:2021-07-29 13:14:04

标签: android kotlin android-architecture-navigation android-jetpack-navigation android-navigation-graph

当我们打开应用程序时,我会显示一个介绍片段。一段时间后,在介绍片段中,我将用户导航到提要片段。在用户按下后退按钮时的提要片段上,我需要显示一个退出对话框。当用户点击退出时,我需要关闭应用。

这是我的导航图。

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

就是这样。我的开始目的地是介绍片段。我有一个操作,它将我导航到提要片段。当我导航到提要片段时,我会弹出我的介绍片段。

关于代码,在介绍片段中,我在 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()
}

但是当我点击退出按钮时,它返回到我弹出的介绍片段。那么为什么它没有弹出,我做错了什么?

---编辑---

一种解决方案是删除 dispatcherCallback 并调用 onBackPressed(),但我认为这不是一个好方法。

val onBackPressedCallback = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            // Show exit dialog
        }
    }
    
requireActivity().onBackPressedDispatcher.addCallback(
    viewLifecycleOwner, onBackPressedCallback 
)
    
fun onExit() {
    onBackPressedCallback.remove()
    activity?.onBackPressed()
}

谢谢。

1 个答案:

答案 0 :(得分:0)

一段时间后,我找到了解决方案,也许这会对某人有所帮助。所以片段没有弹出的问题是,因为当我们的 backstack 中只有一个片段,或者我们尝试弹出我们的起始目标片段时,navigateUp() 函数将返回 false 并且片段将不会弹出。那么为什么会这样呢?因为 navigateUp 导航到导航主机中的上一个片段。但是如果没有片段,我们的导航控制器可以导航到哪里,它只会返回 false。所以我们需要一个函数来确定这是否是我们图中唯一的片段,我们不能向上导航,或者我们可以。因为每次都调用 activity?.onBackPressed() 并不是一个好的解决方案。所以为了实现这一点,我们可以创建一个这样的扩展函数:

fun NavController.navigateUpOrFinish(activity: FragmentActivity): Boolean {
    return if (navigateUp()) {
        true
    } else {
        activity.finish()
        true
    }
}

仅此而已。现在我们可以在对话框退出点击调用这个函数了

fun onExit() {
    findNavController().navigateUpOrFinish(requireActivity())
}

如果有一个我们可以导航的片段,它会在其他情况下调用 navigateUp(),它只会调用 backPressed 并且我们的应用程序将被关闭。谢谢。