【问题标题】:How to cancel fragment navigation (using NavController)如何取消片段导航(使用 NavController)
【发布时间】:2019-09-04 14:51:07
【问题描述】:

我为应用使用了默认的 Android Studio 3.5“导航抽屉”模板。该模板使用“新”(?) NavigationController 在来自 Navigation Drawer 的一组示例片段之间导航。

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

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

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

这将设置片段之间的基本导航。现在,当我添加这一行时:

navView.setNavigationItemSelectedListener(this)

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

所以也许有人可以告诉我是否有办法在某些条件下取消这种导航,而不必自己实现片段导航?

PS:顺便说一句,我还需要导航抽屉中的两个项目来实际打开单独的活动,这与谷歌传播的“单一活动”模式相矛盾,但在我的情况下实际上是必需的。删除我在上面添加的行当然会导致无法按预期对导航抽屉中的其他项目做出反应。

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

【问题讨论】:

    标签: android android-fragments navigation-drawer


    【解决方案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 开发人员指南链接。

    【讨论】:

    • 哇,这听起来是个不错的解决方案。我试试看!
    猜你喜欢
    • 2021-05-02
    • 2020-08-08
    • 2019-03-12
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多