本文最后更新于:1 个月前
设置使用户能够改变应用的功能和行为。设置可以影响后台行为,例如应用与云同步数据的频率;设置的影响还可能更为深远,例如改变用户界面的内容和呈现方式。
- 创建层次结构(XML & 代码)
- 查找偏好设置
- 读取偏好设置值
- 偏好设置操作(Intent & onPreferenceClickListener)
- 监听偏好设置值的更改
- 偏好设置数据存储
- 偏好设置组件
设置使用入门(概览)
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()
。
当用户点按带有关联 Fragment
的 Preference
时,系统会调用接口 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
。
控制偏好设置可见性
要仅在符合某项条件时显示
Preference
,首先要在 XML 中将 可见性设置为 false。当符合相应条件时,在
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()
注册监听器。
为正确管理 Activity
或 Fragment
的生命周期,需要在 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
}
}
由于包含数据存储的 Fragment
或 Activity
可能会在保留值的过程中被销毁,因此应该序列化数据,以免丢失用户更改的任何值。
启用数据存储
实现数据存储后,必须在 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
- 保留一组String
的Preference
。用户可在一个对话框中更改这些值,该对话框包含一列带有对应标签的复选框。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 协议 ,转载请注明出处!