本文最后更新于:1 个月前

设置使用户能够改变应用的功能和行为。设置可以影响后台行为,例如应用与云同步数据的频率;设置的影响还可能更为深远,例如改变用户界面的内容和呈现方式。

设置使用入门(概览)

implementation 'androidx.preference:preference:1.1.1'

创建层次结构

将层次结构定义为 XML 资源

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

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

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

</PreferenceScreen>

注意:

  • 根标签必须为 <PreferenceScreen>,XML 资源必须放置于 res/xml/ 目录。
  • 构建层次结构时,每个 Preference 都应配有唯一的密钥 app:key

通过代码构建层次结构

扩充层次结构

若要从 XML 属性中扩充层次结构,则需要先创建一个 PreferenceFragmentCompat,替换 onCreatePreferences(),然后提供 XML 资源进行扩充,如以下示例所示:

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

然后将此 Fragment 添加到 Activity

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    supportFragmentManager
            .beginTransaction()
            .replace(R.id.settings_container, SettingsFragment())
            .commit()
}

整理设置

偏好设置类别

如果单个屏幕上有多个相关的 Preferences,可以使用 PreferenceCategory 进行分组。

<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>

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

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

要关联带有 Preference 的屏幕,可以在 XML 中声明 app:fragment,或使用 Preference.setFragment()

当用户点按带有关联 FragmentPreference 时,系统会调用接口 PreferenceFragmentCompat.OnPreferenceStartFragmentCallback.onPreferenceStartFragment()。此方法应该用于显示新屏幕,且应在托管 Activity 中实现。

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
    }
}

使用单独的 Activity

自定义设置

查找偏好设置

要访问单独的 Preference,可以使用 PreferenceFragmentCompat.findPreference()。此方法会在整个层次结构中搜索具有指定键的 Preference

控制偏好设置可见性

  1. 要仅在符合某项条件时显示 Preference,首先要在 XML 中将 可见性设置为 false。

  2. 当符合相应条件时,在 onCreatePreferences() 中将 Preference 可见性(isVisible)设置为 true。

动态更新摘要

使用 SimpleSummaryProvider

  • app:useSimpleSummaryProvider="true"
  • Preference.SimpleSummaryProvider.getInstance()

使用自定义 SummaryProvider

onCreatePreferences() 中,新建 SummaryProvider,然后替换 provideSummary() 以返回要显示的摘要:

<EditTextPreference
        app:key="counting"
        app:title="Counting preference"/>
val countingPreference: EditTextPreference? = findPreference("counting")

countingPreference?.summaryProvider = SummaryProvider<EditTextPreference> { preference ->
    val text = preference.text
    if (TextUtils.isEmpty(text)) {
        "Not set"
    } else {
        "Length of saved value: " + text.length
    }
}

Preference 摘要现在显示已保存值的长度,如果不存在已保存值,则显示“Not set”。

自定义 EditTextPreference 对话框

onCreatePreferences() 中新建 OnBindEditTextListener,然后替换 onBindEditText() 以自定义系统向用户显示的 EditText

偏好设置操作

在点按时,Preference 可产生特定操作。若要为 Preference 添加操作,可以直接在 Preference 上设置 Intent,或为更具体地逻辑设置 OnPreferenceClickListener

设置 Intent

  • 在 XML 中嵌套 <intent><intent> 中可设置子元素 <extra>

    <Preference
            app:key=”activity”
            app:title="Launch activity">
        <intent
                android:targetPackage="com.example"
                android:targetClass="com.example.ExampleActivity"/>
    </Preference>
  • Preference 上直接使用 setIntent()

    val intent = Intent(context, ExampleActivity::class.java)
    activityPreference.setIntent(intent)

onPreferenceClickListener

使用已保存的值

如何存储和使用由 Preference 库保存的 Preference 值。

偏好设置数据存储

SharedPreferences

默认情况下,Preference 使用 SharedPreferences 保存值。
对于在应用会话运行期间保存的文件,可通过 SharedPreferences API 读取和写入简单的键值对。
Preference 库使用不公开的 SharedPreferences 实例。

使用 SharedPreferences 保存 Preference 的值时,所用键与为 Preference 设置的键相同。

PreferenceDataStore

如果应用具有特定于设备的配置选项,设备上的每个用户都会有单独的设置,此时 SharedPreferences 就不是太理想的解决方案。

读取偏好设置值

要检索正在使用的 SharedPreferences 对象,可以调用 PreferenceManager.getDefaultSharedPreferences()

监听偏好设置值的更改

要监听 Preference 值得更改,可以在以下两个接口中选择一个:

下表说明了两个接口的差别:

OnPreferenceChangeListener OnSharedPreferenceChangeListener
针对每个偏好设置进行设置 应用于所有偏好设置
当某个偏好设置即将要更改其已保存值时进行调用。这包括待处理值与当前已保存值相同的情况。 仅在偏好设置的已保存值发生更改时调用。
仅通过 Preference 库调用。应用的其他部分可能会更改已保存值。 每当已保存值发生更改时调用,即使是来自应用的其他部分。
在待处理值保存之前调用。 在值已保存之后调用。
在使用 SharedPreferences 或 PreferenceDataStore 时调用。 仅在使用 SharedPreferences 时调用。

OnSharedPreferenceChangeListener

使用此接口时,需要通过 registerOnSharedPreferenceChangedListener() 注册监听器。

为正确管理 ActivityFragment 的生命周期,需要在 onResume()onPause() 回调中注册和取消注册此监听器。

使用自定义数据存储

实现数据存储

创建一个扩展 PreferenceDataStore 的类,以下示例创建了一个处理 String 值得数据存储:

class DataStore : PreferenceDataStore() {
    override fun putString(key: String, value: String?) {
        // Save the value somewhere
    }

    override fun getString(key: String, defValue: String?): String? {
        // Retrieve the value
    }
}

由于包含数据存储的 FragmentActivity 可能会在保留值的过程中被销毁,因此应该序列化数据,以免丢失用户更改的任何值。

启用数据存储

实现数据存储后,必须在 onCreatePreferences() 中设置新的数据存储,以便 Preference 对象使用数据存储来保留值,而不是使用默认的 SharedPreferences。可以为每个 Preference 或整个层次结构启用数据存储。

  • 为特定 Preference 启用自定义数据存储,需要对特定 Preference 调用 setPreferenceDataStore()

    val preference: Preference? = findPreference("key")
    preference?.preferenceDataStore = dataStore
  • 为整个层次结构启用自定义数据存储,需要对 PreferenceManager 调用 setPreferenceDataStore()

    val preferenceManager = preferenceManager
    preferenceManager.preferenceDataStore = dataStore

为特定 Preference 设置的数据存储会替换针对相应层次结构设置的任何数据存储。在大多数情况下,应为整个层次结构设置数据存储。

注意:如果在某个 Preference 附加到层次结构之后为该 Preference 设置数据存储,则 Preference 的初始值将不再传播。

在代码中构建层次结构

可以在 onCreatePreferences() 中以编程方式创建层次结构:

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
    val context = preferenceManager.context
    val screen = preferenceManager.createPreferenceScreen(context)

    val notificationPreference = SwitchPreferenceCompat(context)
    notificationPreference.key = "notifications"
    notificationPreference.title = "Enable message notifications"

    val feedbackPreference = Preference(context)
    feedbackPreference.key = "feedback"
    feedbackPreference.title = "Send feedback"
    feedbackPreference.summary = "Report technical issues or suggest new features"

    screen.addPreference(notificationPreference)
    screen.addPreference(feedbackPreference)

    preferenceScreen = screen
}

添加 PreferenceCategory 的方法与此类似。切记要将子级添加到 PreferenceCategory,而不是根 PreferenceScreen

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
    val context = preferenceManager.context
    val screen = preferenceManager.createPreferenceScreen(context)

    val notificationPreference = SwitchPreferenceCompat(context)
    notificationPreference.key = "notifications"
    notificationPreference.title = "Enable message notifications"

    val notificationCategory = PreferenceCategory(context)
    notificationCategory.key = "notifications_category"
    notificationCategory.title = "Notifications"
    screen.addPreference(notificationCategory)
    notificationCategory.addPreference(notificationPreference)

    val feedbackPreference = Preference(context)
    feedbackPreference.key = "feedback"
    feedbackPreference.title = "Send feedback"
    feedbackPreference.summary = "Report technical issues or suggest new features"

    val helpCategory = PreferenceCategory(context)
    helpCategory.key = "help"
    helpCategory.title = "Help"
    screen.addPreference(helpCategory)
    helpCategory.addPreference(feedbackPreference)

    preferenceScreen = screen
}

偏好设置组件和属性

常用 Preference 组件和属性。

偏好设置组件

偏好设置基础框架

PreferenceFragmentCompat - 负责显示 Preference 对象的互动层次结构的 Fragment

偏好设置容器

  • PreferenceScreen - 设置屏幕的顶层容器,Preference 层次结构的根组件。
  • PreferenceCategory - 对类似的 Preference 进行分组的容器。PreferenceCategory 显示类别标题,并直观划分 Preferences 的组别。

单独偏好设置

  • Preference - 代表单独设置的基本构建块。如果 Preference 设置为保留,则其拥有相应的键值对来保存用户对设置的选择,让用户在应用的其他位置也可以访问此设置。
  • EditTextPreference - 保留 String 值的 Preference。用户可点按 Preference 启动包含文本字段的对话框,然后通过文本字段更改保留值。
  • ListPreference - 保留 String 值的 Preference。用户可在一个对话框中更改此值,该对话框包含一列带有对应标签的单选按钮。
  • MultiSelectListPreference - 保留一组 StringPreference。用户可在一个对话框中更改这些值,该对话框包含一列带有对应标签的复选框。
  • SeekBarPreference - 保留整数值的 Preference。用户可通过拖动 Preference 布局中显示的对应拖动条更改此值。
  • SwitchPreferenceCompat - 保留布尔值的 Preference。用户可通过与对应的开关微件互动或点按 Preference 布局更改此值。
  • CheckBoxPreference - 保留布尔值的 Preference。用户可通过与对应的复选框互动或点按 Preference 布局更改此值。

偏好设置属性

通用属性

  • title - 表示 Preference 标题的 String 值。
  • summary - 表示 Preference 摘要的 String 值。
  • icon - 表示 Preference 图标的 Drawable
  • key - String 值,表示用于保留关联 Preference 值的键。键使得能够在运行时进一步自定义 Preference。应为层次结构中的每个 Preference 设置键。
  • enabled - 指示用户能否与 Preference 互动的布尔值。
  • isPreferenceVisible 指示 Preference 类别是否可见的布尔值。
  • defaultValue - Preference 的默认值。
  • dependency - 表示 SwitchPreferenceCompat 的键,它会控制此 Preference 的状态。当对应开关关闭时,此 Preference 停用,且无法修改。

PreferenceCategory 属性

initialExpandedChildrenCount - 启用展开式 Preference 行为的整数值。此值表示 PreferenceGroup 中所显示子级的最大数量。系统会收起所有多余子级,用户可以点按展开按钮查看。默认情况下,此值为 Integer.MAX_VALUE,且系统会显示所有子级。

ListPreference / MultiSelectListPreference 属性

  • entries - 对应要向用户显示的列表条目的 String 数组。这些值中的每一个都通过索引与内部保留的值数组对应。例如,当用户选择第一个列表条目时,系统将保留对应值数组中的第一个元素。
  • entryValues - 要保留的条目数组。这些值中的每一个都通过索引与显示给用户的列表条目数组对应。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

Android Studio 插件 上一篇
Handler 下一篇