Android: 如何让设置菜单与 NavigationUI 一起显示?

Android: How do I get the Settings menu to appear with NavigationUI?

我正在尝试遵循这个:https://developer.android.com/guide/navigation/navigation-ui along with a review of https://codelabs.developers.google.com/codelabs/android-navigation/#8(尽管第二个 link 在 Kotlin 中,我在 Javascript 中编码)在 [=32] 中实现一个应用程序=] 左侧有导航抽屉,右上角有一个设置按钮(首选项)。

我正在为抽屉和设置中的每个选项使用带片段的 NavigationUI。

我的问题是我的设置片段没有出现。我想我快到了,但是尽管查看了几篇文章和问题还是无法让它发挥作用。

此代码允许我从导航抽屉切换片段:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    DrawerLayout drawer = findViewById(R.id.drawer_layout);
    NavigationView navigationView = findViewById(R.id.nav_view);
    mAppBarConfiguration = new AppBarConfiguration.Builder(
            R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow)
            .setDrawerLayout(drawer)
            .build();
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(navigationView, navController);
    //NavigationUI.setupWithNavController(toolbar, navController, mAppBarConfiguration);
}

如果我在最后两行切换注释代码(所以我执行最后一行而不是倒数第二行)以匹配指南,则片段切换失败。

我处理设置菜单的代码是:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.

    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    return NavigationUI.onNavDestinationSelected(item, navController)
            || super.onOptionsItemSelected(item);
/*
    int id = item.getItemId();
    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        // TODO: Do something to accept settings
        View contextView =  findViewById(R.id.nav_host_fragment); // Apparently any layout can be used
        Snackbar.make(contextView, "Settings", Snackbar.LENGTH_LONG)
                .setAction("Action", null).show();
        //changeFragment(new SettingsFragment());
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.nav_host_fragment, new SettingsFragment(), "nh")
                .addToBackStack("nh")
                .commit();
        return true;
    }
    return super.onOptionsItemSelected(item);
*/
}

活动部分与上面的指南相符,正在调用(通过设置断点证明)但什么也没做。

如果我选择将其切换为注释掉的代码,那么我的设置片段会出现但会覆盖当前片段。我从另一个答案了解到,这是因为我使用两种不同的方法来处理片段可见性,这是​​有道理的,也是我试图让 NavigationUI 框架处理我的设置片段的原因。

我觉得治愈一定很简单,但是看了一遍又一遍的指南(很多答案都无法解决)

您有不同的选择:

只需在您的导航图中定义 SettingsFragment

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!--Your fragments-->


    <!--Settings fragment-->
    <fragment
        android:id="@+id/settingsFragment"
        android:name=".SettingsFragment"/>

</navigation>

然后用以下方法扩充你的菜单:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

在您的菜单中使用图表中使用的相同 ID:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/settingsFragment"
        .../>

</menu>

最后覆盖onOptionsItemSelected方法:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    return NavigationUI.onNavDestinationSelected(item, navController)
            || super.onOptionsItemSelected(item);
}

你也可以定义一个Global Action.

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">



    <!--Global action-->
    <action android:id="@+id/action_global_open_settings_fragment"
        app:destination="@id/settingsFragment"/>

</navigation>

然后在您的代码中导航到目的地只需使用:

Navigation.findNavController(view).navigate(R.id.action_global_open_settings_fragment);

我不确定我是否理解你的问题。但这是我的解决方案,希望对您有所帮助。

这是我的导航图

这是准则。如您所见,我在 SettingsFragment:

中有一个动作
    <fragment
    android:id="@+id/settingsFragment"
    android:name="packageName.SettingsFragment"
    android:label="Settings Fragment">
    <action
        android:id="@+id/actionSettingsToPassword"
        app:destination="@id/passwordDialogFragment"
        app:enterAnim="@anim/fragment_open_enter"
        app:exitAnim="@anim/fragment_open_exit" />

这是我的 bottomNavigationMenu XML:

<item
    android:id="@+id/settingsFragment"
    android:icon="@drawable/ic_settings"
    android:title="Settings" />

请记住,导航和菜单中的 ID 应该相同。 正如您在代码中看到的,“设置片段”的 ID 是一样的:

    android:id="@+id/settingsFragment"

我不知道你是否知道如何在你的资源中添加preferences.xml。当然我也写了:

Right Click on "res" New > Android Resource Directory

在“资源类型”字段中,取件 XML。现在你将在“res”下有 xml 文件夹。再次:

Right Click on "xml" New > XML Recourse File

现在,这是我的“preferences.xml”:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="Weather Location">
    <SwitchPreference
        android:defaultValue="true"
        android:disableDependentsState="true"
        android:key="USE_DEVICE_LOCATION"
        android:summary="Allow The App To Get Your Location"
        android:title="Use Device Location" />
    <EditTextPreference
        android:defaultValue="Tehran"
        android:dependency="USE_DEVICE_LOCATION"
        android:key="CUSTOM_LOCATION"
        android:summary="The Location For Which The Weather Is Displayed"
        android:title="Location" />
</PreferenceCategory>
<PreferenceCategory android:title="Units">
    <ListPreference
        android:defaultValue="METRIC"
        android:entries="@array/unitSystemEntries"
        android:key="UNIT_SYSTEM"
        android:summary="%s"
        android:title="Unit System"
        android:entryValues="@array/unitSystemValues"/>
</PreferenceCategory>
</PreferenceScreen>

然后创建一个“Kotlin”或“Java”class 并将 XML 设置为您的 class 像这样 (取决于哪个你写的语言):

class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
    addPreferencesFromResource(R.xml.preferences)
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    (activity as? AppCompatActivity)?.supportActionBar?.title = "Settings"
    (activity as? AppCompatActivity)?.supportActionBar?.subtitle = null
}
}

这是我的申请 Class:

class ForecastApplication : Application(){
override fun onCreate() {
    super.onCreate()
    PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
}
}

并在您应用程序的清单中,在应用程序标签内,定义您已经创建的应用程序 class。

        android:name=".ForecastApplication"

希望这就是您所需要的。