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

时间:2019-09-04 14:51:07

标签: android android-fragments navigation-drawer

我已经为应用程序使用了默认的Android Studio 3.5“导航抽屉”模板。该模板使用“新”(?)NavigationController在导航抽屉中的一组示例片段之间进行导航。

虽然我非常喜欢它的工作方式,但是我正在寻找一种方法,以防止在当前片段很脏的情况下导航到另一个片段(例如:包含未保存的更改)。到目前为止,我还无法弄清楚如何进行这项工作。似乎没有任何事件可让我取消导航。

我还试图在模板生成的以下代码中添加另一行:

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

这将在片段之间建立基本导航。现在,当我添加以下行时:

navView.setNavigationItemSelectedListener(this)

当确实选择了另一个项目时,我确实会收到通知,但这完全禁用了导航,因为先前由navView.setupWithNavController(navController)设置的监听器已由this替换。

所以也许有人可以启发我是否有某种方法可以在某些条件下取消这种导航,而不必自己执行片段导航?

PS:在旁注中,我还需要导航抽屉中的两个项目才能实际打开单独的活动,这与Google传播的“单个活动”模式相抵触,但在我的情况下实际上是必需的。当然,删除我在上面添加的行会导致无法对导航抽屉中的其他项目做出预期的反应。

也许整个方法都不适合我的情况?

1 个答案:

答案 0 :(得分:1)

听起来您想实现Conditional Navigation

也就是说,要实现您的要求,您可以扩展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
    }
}

要使用此功能,请在您的活动布局中替换

...
    <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" />
...

使用新类,并保留以下属性:

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

然后,在您的活动中,您可以使用新的预览侦听器有条件地取消导航:

...
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
            })
        ...
    }
    ...
}

注意:仅适用于抽屉的NavigationView部分,它不会让您取消NavController触发的导航。为此,请参阅此答案顶部的“ Android开发人员指南”链接。