tl/dr:您应该遵循将目的地与菜单项文档联系起来 https://developer.android.com/guide/navigation/navigation-ui#Tie-navdrawer并使用NavigationUI.onNavDestinationSelected()
获得正确的行为:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
NavController navController = Navigation.findNavController(this,
R.id.nav_host_fragment_content_main);
// By calling onNavDestinationSelected(), you always get the right behavior
return NavigationUI.onNavDestinationSelected(item, navController)
|| super.onOptionsItemSelected(item);
}
Why
导航2.4用途多个后退堆栈 https://medium.com/androiddevelopers/navigation-multiple-back-stacks-6c67ba41952f与你的每个元素相关联NavigationView
根据添加抽屉式导航指南 https://developer.android.com/guide/navigation/navigation-ui#add_a_navigation_drawer:
开始于导航2.4.0-alpha01 https://developer.android.com/jetpack/androidx/releases/navigation#2.4.0-alpha01,当您使用 setupWithNavController 时,每个菜单项的状态都会被保存和恢复。
这意味着“主”屏幕有一个与之关联的后堆栈,当您点击该图标时,该后堆栈会恢复,画廊、幻灯片和设置也是如此。这就是该项目的状态保存方式。
这意味着每次点击抽屉中的项目不仅会导航到该屏幕,还会交换与该项目关联的整个后堆栈 - 您从第一个屏幕导航到的所有内容。
所以当你打电话时Navigation.findNavController(this, R.id.nav_host_fragment_content_main).navigate(R.id.nav_settings);
,您所做的事情与选择抽屉中的“设置”项目不同 - 您只是将“设置”屏幕添加到“主”屏幕的后堆栈中。这就是为什么点击“主页”图标不会执行任何操作 - 您已经位于“主”屏幕的后堆栈上。
您真正想要做的是交换到与 nav_settings 项关联的完全独立的返回堆栈。这会将 nav_settings 返回堆栈与主页返回堆栈分开,从而确保点击主页图标可返回主屏幕的返回堆栈。
这正是NavigationUI.onNavDestinationSelected() https://developer.android.com/reference/androidx/navigation/ui/NavigationUI#onNavDestinationSelected(android.view.MenuItem,androidx.navigation.NavController)API 所做的(因为这正是setupWithNavController
API 使用),因此您可以直接在您的onOptionsItemSelected()
.
但是,如果您想手动调用navigate()
(顺便说一句,这意味着您没有获得使用时默认获得的交叉淡入淡出动画onNavDestinationSelected
),您可以添加保存状态标志 https://developer.android.com/guide/navigation/navigation-navigate#savestate到您的导航呼叫以编程方式应用 NavOptions https://developer.android.com/guide/navigation/navigation-navigate#programmatic:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Bundle bundle =new Bundle();
switch (item.getItemId()) {
case R.id.action_settings:
{
// Manually build the NavOptions that manually do
// what NavigationUI.onNavDestinationSelected does for you
NavOptions navOptions = new NavOptions.Builder()
.setPopUpTo(R.id.nav_home, false, true)
.setRestoreState(true)
.build();
NavController navController = Navigation.findNavController(this,
R.id.nav_host_fragment_content_main);
navController.navigate(R.id.nav_settings, navOptions);
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
请注意,setupWithNavController
API 依赖于嵌套图 https://developer.android.com/guide/navigation/navigation-nested-graphs当前目的地的信息来确定选择哪个项目 - 期望“主页”选项卡中的所有目的地都是“主页”导航图的一部分。因为你已经切换到 nav_settings,setupWithNavController
假设您已交换到该后堆栈。由于您实际上还没有这样做,这就是为什么您选择的项目与您所在的后堆栈不同步。