使用导航组件的特定片段的自定义 "navigate up" 行为

Custom "navigate up" behavior for certain fragment using Navigation component

我想使用导航组件

从片段中添加自定义向上导航

在我的 build.gradle(app) 中,我使用 androidx.appcompat:appcompat:1.1.0-alpha04 依赖项从 activity.

访问 onBackPressedDispatcher

所以我在我的片段中实现了 OnBackPressedCallback 并且 向调度程序注册回调:

requireActivity().onBackPressedDispatcher.addCallback(this)

我原以为在工具栏中按 向上导航 会调用它,但事实并非如此。 按设备的后退按钮按预期调用它。

是否有类似的方法可以在片段中添加一些关于向上导航操作的回调?

更新

覆盖的方法 onOptionsItemSelectedonSupportNavigateUp 不会在按下工具栏中的 向上按钮 时调用

这样给工具栏后退按钮添加点击事件

@Override
public boolean onOptionsItemSelected(MenuItem item) {
 switch (item.getItemId()) {
case android.R.id.home:
    // Toolbar back button pressed, do something you want    

default:
    return super.onOptionsItemSelected(item);
  }
}

另一种方式

  Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    // Title and subtitle
    toolbar.setNavigationOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // Toolbar back button pressed, do something you want    
        }
    });

您需要从 onBackPressedDispatcher 属性 调用 onBackPressed()。假设您的工具栏设置正确,您可以在 Activity.

中使用下面的代码
override fun onOptionsItemSelected(menuItem : MenuItem?) : Boolean {
    if (menuItem.getItemId() == android.R.id.home) {
        onBackPressedDispatcher.onBackPressed()
        return true // must return true to consume it here

    }
    return super.onOptionsItemSelected(menuItem)
}

片段覆盖

override fun onAttach(context: Context) {
        super.onAttach(context)            

        //enable menu
        setHasOptionsMenu(true)

        requireActivity()
                .onBackPressedDispatcher
                .addCallback(this){
                   //true means that the callback is enabled
                    this.isEnabled = true
                    exitDialog() //dialog to conform exit
                }
    }

这是做什么的:

Trigger a call to the currently added OnBackPressedCallback callbacks in reverse order in which they were added. Only if the most false from its OnBackPressedCallback#handleOnBackPressed() will any previously added callback be called.

我在示例中使用的是 AndroidX,因此我的导入看起来像

import androidx.appcompat.app.AppCompatActivity.

我找到了解决方案

handleOnBackPressed() 方法仅在设备的后退按钮单击时调用。 我想知道,为什么在工具栏中按 "up button" 时没有调用 onOptionsItemSelected()onSupportNavigateUp() 方法。答案是我用

NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration)

在 activity 中设置带有导航组件的工具栏。 这使得工具栏可以响应内部导航,按下 "up button" 不会调用 activity 或片段中的任何重写方法。

应该改用

NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration)

这将使 actionBar 响应导航,因此我可以使用覆盖函数 onOptionsItemSelected()onSupportNavigateUp() 在"up button"点击特定屏幕时添加自定义行为的最佳位置(在我的例子中)是

onSupportNavigateUp()

的托管 activity,这样

override fun onSupportNavigateUp(): Boolean {
        val navController = this.findNavController(R.id.mainNavHostFragment)
        return when(navController.currentDestination?.id) {
            R.id.destinationOfInterest -> {
                // custom behavior here 
                true
            }
            else -> navController.navigateUp()
        }
}

但值得一提的是,如果您想直接在片段中实现自定义行为,@Enzokie 的回答应该很有魅力

此设置也有效,您无需在 activity:

中覆盖 onSupportNavigateUp
NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration)
toolbar.setNavigationOnClickListener {
    if (navController.currentDestination?.id == R.id.destinationOfInterest) {
        // Custom behavior here
    } else {
        NavigationUI.navigateUp(navController, configuration)
    }
}

我更喜欢设置 Toolbar,因为它会自动处理向上导航和 open/close DrawerLayout(如果有的话)。

我自定义了(直接在Fragment中)工具栏上的backbress,步骤如下:

1. onCreate [Activity]:

NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration)

2。 onSupportNavigateUp [Activity]:

override fun onSupportNavigateUp(): Boolean {
        onBackPressedDispatcher.onBackPressed()
        return super.onSupportNavigateUp()
    }

3。自定义或禁用 backpress [Fragment]:

requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
           isEnabled = false
           // enable or disable the backpress
       }