整理设置   Android Jetpack 的一部分。

如果设置屏幕庞大繁杂,用户将难以找到想要更改的具体设置。Preference 库可以从以下方面帮助您更好地整理设置屏幕。

偏好设置类别

如果单单一个屏幕上就有多个相关的 Preferences,您可以使用 PreferenceCategory 将它们归为一组。每个 PreferenceCategory 都会显示一个类别标题,并在视觉上与其他元素区分开来。

如需在 XML 中定义 PreferenceCategory,请使用 PreferenceCategory 封装 Preference 标记,如下所示:

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

    <PreferenceCategory
        app:key="notifications_category"
        app:title="Notifications">

        <SwitchPreferenceCompat
            app:key="notifications"
            app:title="Enable message notifications"/>

    </PreferenceCategory>

    <PreferenceCategory
        app:key="help_category"
        app:title="Help">

        <Preference
            app:key="feedback"
            app:summary="Report technical issues or suggest new features"
            app:title="Send feedback"/>

    </PreferenceCategory>

</PreferenceScreen>
图 1. 按类别划分的偏好设置。

将层次结构拆分为多个屏幕

如果您有大量的 Preferences 或泾渭分明的类别,可以分不同的屏幕显示。每个屏幕都应该是一个 PreferenceFragmentCompat,拥有自己单独的层次结构。然后,初始屏幕上的 Preferences 可关联至含有相关 Preferences 的子屏幕。

图 2 显示了一个简单的层次结构,它包含两个类别:“Messages”和“Sync”。

图 2. 包含两个类别的简单层次结构。

图 3 显示了拆分为多个屏幕的同一组 Preferences

图 3. 拆分为多个屏幕的层次结构。

如需关联含有 Preference 的屏幕,您可以在 XML 中声明 app:fragment,或使用 Preference.setFragment()。设置应在点按 Preference 时启动的 PreferenceFragmentCompat 的完整软件包名称,如下所示:

<Preference
        app:fragment="com.example.SyncFragment"
        .../>

当用户点按带有关联 FragmentPreference 时,系统会调用接口方法 PreferenceFragmentCompat.OnPreferenceStartFragmentCallback.onPreferenceStartFragment()。您应在该元素所在的 Activity 中实现此方法,并在此方法中处理显示新屏幕的操作。

典型实现一般如下所示:

Kotlin

class MyActivity : AppCompatActivity(),
    PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {

    ...

    override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean {
        // Instantiate the new Fragment
        val args = pref.extras
        val fragment = supportFragmentManager.fragmentFactory.instantiate(
                classLoader,
                pref.fragment)
        fragment.arguments = args
        fragment.setTargetFragment(caller, 0)
        // Replace the existing Fragment with the new Fragment
        supportFragmentManager.beginTransaction()
                .replace(R.id.settings_container, fragment)
                .addToBackStack(null)
                .commit()
        return true
    }
}

Java

public class MyActivity extends AppCompatActivity implements
        PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {

    ...

    @Override
    public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {
        // Instantiate the new Fragment
        final Bundle args = pref.getExtras();
        final Fragment fragment = getSupportFragmentManager().getFragmentFactory().instantiate(
                getClassLoader(),
                pref.getFragment());
        fragment.setArguments(args);
        fragment.setTargetFragment(caller, 0);
        // Replace the existing Fragment with the new Fragment
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.settings_container, fragment)
                .addToBackStack(null)
                .commit();
        return true;
    }
}

PreferenceScreens

系统不再支持在同一 XML 资源中使用嵌套的 <PreferenceScreen> 来声明嵌套层次结构。您应改用嵌套的 Fragment 对象。

使用单独的 activity

相对地,如果您需要深入自定义每个屏幕,或者希望在各个屏幕之间切换时执行完整的 Activity 转换,则可以为每个 PreferenceFragmentCompat 使用单独的 Activity。这样一来,您就可以全面自定义每个 Activity 及其对应的设置屏幕。对于大多数应用,不建议这么做,而应使用前面介绍的 Fragments

如需详细了解如何从 Preference 启动 Activities,请参阅偏好设置操作