简体   繁体   English

如何取消片段导航(使用NavController)

[英]How to cancel fragment navigation (using NavController)

I've used the default Android Studio 3.5 "Navigation Drawer" template for an app. 我已经为应用程序使用了默认的Android Studio 3.5“导航抽屉”模板。 That template uses the "new" (?) NavigationController for navigating between a set of sample fragments from the Navigation Drawer. 该模板使用“新”(?)NavigationController在导航抽屉中的一组示例片段之间进行导航。

While I pretty much love the way it works, I'm looking for a way to prevent navigating to another fragment if the current fragment is dirty (for example: contains unsaved changes). 虽然我非常喜欢它的工作方式,但是我正在寻找一种方法,以防止在当前片段很脏的情况下导航到另一个片段(例如:包含未保存的更改)。 So far I've not been able to figure out how to make that work. 到目前为止,我还无法弄清楚如何进行这项工作。 There don't seem to be any events that allow me to cancel navigation. 似乎没有任何事件可让我取消导航。

I've also tried to add another line to the following code generated by the template: 我还尝试将另一行添加到模板生成的以下代码中:

setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)

This sets up basic navigation between the fragments. 这将在片段之间建立基本导航。 Now, when I add this line: 现在,当我添加以下行时:

navView.setNavigationItemSelectedListener(this)

I do get notified when another item is selected, but this disables the navigation at all, as the listener previously set by navView.setupWithNavController(navController) is replaced by this . 当选择了另一个项目时,我的确收到通知,但这完全禁用了导航,因为先前由navView.setupWithNavController(navController)设置的侦听器已被this替代。

So maybe somebody could enlighten me as to whether there is a way of cancelling such a navigation under certain conditions without having to implement the fragment navigation myself? 因此,也许有人可以启发我是否有某种方法可以在某些条件下取消这种导航,而不必自己执行片段导航?

PS: On a side note, I also need two items in the navigation drawer to actually open separate activities, which contradicts the "single activity" pattern propagated by Google, but is actually required in my case. PS:在旁注中,我还需要导航抽屉中的两个项目才能实际打开单独的活动,这与Google传播的“单个活动”模式相抵触,但在我的情况下实际上是必需的。 Removing the line I added above of course leads to being unable to react to other items in the navigation drawer as expected. 当然,删除我在上面添加的行会导致无法对导航抽屉中的其他项目做出预期的反应。

Maybe the whole approach ist not suitable in my case? 也许整个方法都不适合我的情况?

This sounds like you want to implement Conditional Navigation . 听起来您想实现条件导航

That said, to implement what you ask, you can extend NavigationView to include a "preview" listener that fires first (Kotlin syntax): 也就是说,要实现您的要求,您可以扩展NavigationView使其包含首先触发的“预览”侦听器(Kotlin语法):

package com.example.myapp

import android.content.Context
import android.util.AttributeSet
import android.view.MenuItem
import com.google.android.material.navigation.NavigationView

class CancellableNavigationView(context: Context, attrs: AttributeSet) :
    NavigationView(context, attrs) {
    private var cancellableListener =
        object : OnNavigationItemSelectedListener {
            var listener: OnNavigationItemSelectedListener? = null
            var prevListener: OnNavigationItemSelectedListener? = null

            override fun onNavigationItemSelected(item: MenuItem): Boolean {
                if (listener?.onNavigationItemSelected(item) == false) {
                    return false
                }
                return prevListener?.onNavigationItemSelected(item) ?: true
            }
        }

    override fun setNavigationItemSelectedListener(
        listener: OnNavigationItemSelectedListener?
    ) {
        cancellableListener.prevListener = listener
        super.setNavigationItemSelectedListener(cancellableListener)
    }

    fun setNavigationItemSelectedPreviewListener(
        listener: OnNavigationItemSelectedListener?
    ) {
        cancellableListener.listener = listener
    }
}

To use this, in your activity layout replace 要使用此功能,请在您的活动布局中替换

...
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />
...

with the new class, keeping the attributes: 使用新类,保留以下属性:

...
    <com.example.myapp.CancellableNavigationView
        android:id="@+id/nav_view"
        ... />
...

Then, in your activity, you can use the new preview listener to conditionally cancel the navigation: 然后,在您的活动中,可以使用新的预览侦听器有条件地取消导航:

...
class MainActivity : AppCompatActivity() {
    private lateinit var appBarConfiguration: AppBarConfiguration

    fun changesNeedSaving() : Boolean { ... }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        appBarConfiguration = AppBarConfiguration(TOP_LEVEL_NAV, drawer_layout)
        setupActionBarWithNavController(nc, appBarConfiguration)
        nav_view.setupWithNavController(nc)
        nav_view.setNavigationItemSelectedPreviewListener(
            NavigationView.OnNavigationItemSelectedListener { item ->
                Log.d(TAG, "got item: $item")
                !changesNeedSaving() // Conditionally allow navigation
            })
        ...
    }
    ...
}

Caveat: This will only work for the NavigationView part of the drawer, it will not let you cancel the navigation triggered by the NavController . 警告:这仅适用于抽屉的NavigationView部分,它不会让您取消NavController触发的导航。 For that, see the link to the Android Developer Guide at the top of this answer. 为此,请参阅此答案顶部的“ Android开发人员指南”链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Navigation 组件在 Fragment 中初始化 NavController 的位置 - Navigation Component Where to initialize NavController in Fragment 如何使用NavController.navigate替换片段,而不是在顶部添加片段 - How to replace a fragment using NavController.navigate instead of adding it on top 使用 NavController 时如何返回上一个片段? - How do you return to the previous fragment when using a NavController? 如何使用 NavController 为每个片段扩充和收听自定义菜单? - How to inflate and listen a custom menu per fragment using NavController? NavController 如何替换菜单片段 - NavController How to replace menu fragment 使用 Fragment Factory 和 Navigation Component 时 View 没有设置 NavController - View does not have a NavController set when using Fragment Factory and Navigation Component 使用 NavController 从片段导航到另一个片段 - Navigate from fragment to another using NavController 使用 DialogFragment 作为 Android NavController 中的 Fragment 之一 - Using DialogFragment as one of the Fragment in Android NavController 如何在片段和活动中隐藏 NavController 和 AppBarConfiguration - How to hide NavController & AppBarConfiguration in a fragment & activity 如何在不使用 NavController 将片段添加到后台堆栈的情况下导航片段? - How to navigate fragment without adding it into backstack with NavController?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM