mot*_*deh 10 android android-fragments android-studio navigation-drawer
(使用Android Studio 2021.1.1)
action_settings菜单和配置菜单项。onOptionsItemSelected()以MainActivity.java处理设置菜单,如下所示:@Override
public boolean onOptionsItemSelected(MenuItem item) {
Bundle bundle = new Bundle();
switch (item.getItemId()) {
case R.id.action_settings:
Navigation
.findNavController(this, R.id.nav_host_fragment_content_main)
.navigate(R.id.nav_settings);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行项目,抽屉菜单工作正常并按预期打开片段。问题是,当您单击溢出菜单打开设置片段时,它可以工作,但打开主页片段时,抽屉菜单不再工作。
经过一些测试,我发现这是因为依赖版本的原因,将其从2.4.1降级到2.3.5可以解决问题。
我的代码有问题还是因为 API 更改?如何在不降级的情况下处理这个问题?
MainActivity在的方法中onCreate()我添加了以下内容:
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow, R.id.nav_settings)
.setOpenableLayout(drawer)
.build();
Run Code Online (Sandbox Code Playgroud)
app模块的build.gradle:
plugins {
id 'com.android.application'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.example.myapplication"
minSdk 23
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
buildToolsVersion '32.0.0'
ndkVersion '23.1.7779620'
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation 'androidx.navigation:navigation-fragment:2.4.1'
implementation 'androidx.navigation:navigation-ui:2.4.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
}
Run Code Online (Sandbox Code Playgroud)
ian*_*ake 19
tl/dr:您应该遵循将目标链接到菜单项文档并使用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);
}
Run Code Online (Sandbox Code Playgroud)
为什么
根据添加导航抽屉指南, Navigation 2.4 使用与每个元素关联的多个返回堆栈:NavigationView
从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()API 所做的(因为这正是setupWithNavControllerAPI 使用的),因此您可以直接在您的onOptionsItemSelected().
但是,如果您想手动调用navigate()(顺便说一下,这意味着您没有获得使用时默认获得的淡入淡出动画onNavDestinationSelected),您可以通过以编程方式应用 NavOptions将保存状态标志添加到导航调用中:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,setupWithNavControllerAPI 依赖当前目的地的嵌套图来确定选择哪个项目 - 期望“主页”选项卡中的所有目的地都是“主页”导航图的一部分。因此,因为您已经交换到 nav_settings,setupWithNavController所以假设您已经交换到该后堆栈。由于您实际上还没有这样做,这就是为什么您选择的项目与您所在的后堆栈不同步。
| 归档时间: |
|
| 查看次数: |
5336 次 |
| 最近记录: |