Preference的使用(2) --- PreferenceCategory && PreferenceScreen

本文详细介绍了Android Preference系统中的PreferenceGroup、PreferenceCategory与PreferenceScreen类的功能与用法,包括如何设置优先级、启用状态、获取子项以及如何在XML布局文件中使用它们构建复杂的Preference层次结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一节有讲到Preference的基本使用跟API的介绍 ,没有看的话请先阅读 Preference的使用(1)

现在介绍其子类PreferenceCategory  跟 PreferenceScreen,现在看下继承关系

如上图,他们都是继承自PreferenceGroup的先看一下  PreferenceGroup

PreferenceGroup  是一个Preference的集合,可以包含多个Preference,这个从字面意思不难理解

类似View  跟ViewGroup。看其API:

1.public void setOrderingAsAdded(boolean orderingAsAdded)

当一个preference被add进来的时候是否排序,如果是false的话,那么对于那些没有order的将根据里面的preference的order 跟 默认字母进行排序  。在Add一个preference的时候,是不会重新排序的,需要在add之前调用这个方法,应该要在早一点调用这个方法,这个描述好抽象。

2.public boolean isOrderingAsAdded()   当add一个preference的时候是否可以排序

3.public void addItemFromInflater(Preference preference)   被Inflater 调用增加进来

查看源码:

  /**
     * Called by the inflater to add an item to this group.
     */
    public void addItemFromInflater(Preference preference) {
        addPreference(preference);
    }
跟第六点差不多,就是没有返回值而已

4.public int getPreferenceCount()   返回这个group中的preference的个数

5.public Preference getPreference(int index)   返回group的第index元素。

6.public boolean addPreference(Preference preference)   add 一个 preference进来,但是位置跟order是有关系的,返回是否增加成功

7.public boolean removePreference(Preference preference)  从group中移除  返回是否移除成功

8.public void removeAll( ) 移除所有的

9.public Preference findPreference(CharSequence key)   根据Key来找到一个preference,没有找到就返回null

如果有个相同key的preference,那么会返回前一个preference 

10.public void setEnabled(boolean enabled)   group的enable ,如果false 那么这个group里面都无法响应click事件


有些方法不理解的,将在其子类中写使用代码:


现在看子类PreferenceCategory

PreferenceCategory  是一个PreferenceGroup的子类,而且是被禁用的,那么它就不可以被点击了,可以用于分类

在父类的基础上只有一个方法

public boolean isEnabled()  检测是否被enable了
 

PreferenceScreen 代表着preference的层次机构中的最顶层,为了显示这个类,需要一个 PreferenceActivity

指向一个实例化的PreferenceScreen。从中得之,是需要PreferenceActivity来显示的,而且是最顶层的。这个类能出现在2个地方:

1. PreferenceActivity指向它的时候,也就是PreferenceActivity调用addPreferencesFromResource的时候才被当做一个根(可以理解为布局的最外层),但是是没有显示的
2.出现在Preference层次机构内部的时候, 那么它显示出来,并且是当被点击的时候会显示一个对话框形式的Preference 或者直接启动一个Intent。并且它里面的内容不会被显示 很点难理解,后面有试验代码的。官方有一个布局实例
<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:key="first_preferencescreen">
    <CheckBoxPreference
            android:key="wifi enabled"
            android:title="WiFi" />
    <PreferenceScreen
            android:key="second_preferencescreen"
            android:title="WiFi settings">
        <CheckBoxPreference
                android:key="prefer wifi"
                android:title="Prefer WiFi" />
        ... other preferences here ...
    </PreferenceScreen>
</PreferenceScreen> 

现在看看这个API:
1. public ListAdapter getRootAdapter()  返回一个能被加到PreferenceActivity上显示的adapter
这个Adapter的getItem会返回Preference的子类 , 这个PreferenceScreen不会出现在在adapter中,而是出现在这个Pre
PreferenceScreen的上面     不好理解呀
2.public void bind(ListView listView)  把一个ListView跟加进来,是使得ListView 跟getRootAdapter() 绑定,并且可以点击ListView的item
3.public void onDismiss(DialogInterface dialog)  ,前面有说过“出现在Preference层次机构内部的时候, 那么它显示出来,并且是当被点击的时候会显示一个对话框形式的Preference”  ,那么这个回调就是当那个dialog 消失的时候调用的。
4.public Dialog getDialog()  得到对话框  
5.public void onItemClick(AdapterView parent,View view,int position,long id)  当Item被点击的时候的回调
 
基本介绍已结束,现在看一下代码:
1.理解
  
PreferenceActivity指向它的时候,也就是PreferenceActivity调用addPreferencesFromResource的时候才被当做一个根(可以理解为布局的最外层),但是是没有显示的
出现在Preference层次机构内部的时候, 那么它显示出来,并且是当被点击的时候会显示一个对话框形式的Preference 或者直接启动一个Intent。并且它里面的内容不会被显示
对于上面的,我们更改XML
上面说顶层PreferenceScreen 是不会显示的,那么我就把它加上title等信息,
在在内部创建一个PreferenceScreen 点击看其反应:
XMl如下:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="preference  root"
    android:summary="preference root summary"
     >

    <Preference
        android:order="1"
        android:key="preference0"
        android:summary="preference0"
        android:title="preference" 
        android:icon="@drawable/ic_launcher"
        >
    </Preference>
    
    <PreferenceScreen 
        android:title="preference  inside"
        android:summary="preference  inside summary">
        
        <Preference
            android:key="preference3"
            android:order="2"
            android:summary="preference3"
            android:title="preference3" >
        </Preference>
        
        <Preference
            android:key="preference4"
            android:order="2"
            android:summary="preference4"
            android:title="preference4" >
        </Preference>
        
    </PreferenceScreen>
    
     <Preference
        android:order="2"
        android:key="preference1"
        android:summary="preference1"
        android:dependency="preference0"
        android:title="preference1" >
    </Preference>

</PreferenceScreen>
结果截图:

然后在点击一个结果是:


由此可见,顶层的title跟 summary是没有显示的,  内部的PreferenceScreen是不会显示里面的子的Preference,点击才会显示出来。上面还说或者是启动一个Intent 那么就setIntent ,并把preferenceScreen加上Key ”preference screen0

preferenceScreen = (PreferenceScreen) findPreference("preference screen0");
		if (null != preferenceScreen){
			preferenceScreen.setIntent(intentTest);
		}
结果是直接启动了Intent ,没有弹出对话框,如果Intent不存在的话,点击也是不会弹出对话框,而且会报错的

如果Intent 如果不存在的话怎么来 catch呢?代码如下:

preferenceScreen.setOnPreferenceClickListener(new OnPreferenceClickListener() {
			
			@Override
			public boolean onPreferenceClick(Preference preference) {
				Log.i(TAG , "preferenceScreen is clicked ");
				Intent intent = preferenceScreen.getIntent();
				if (null != intent){
					try {
						startActivity(intent);
					} catch (Exception e) {
					}
					return true;
				}
				return false;
			}
		});
思路:如果存在intent的话,那么自己启动,并且return  true(事件不被传递了 ,如果intent错误也就被 catch了)

 public ListAdapter getRootAdapter()
在xml中在增加一个PreferenceScreen 把screen0 中的都加入都 screen1 中
preferenceScreen = (PreferenceScreen) findPreference("preference screen 0");
		preferenceScreen1 = (PreferenceScreen) findPreference("preference screen 1");
		if (null != preferenceScreen){
			adapter = preferenceScreen.getRootAdapter();
			int count = adapter.getCount();
			Log.i(TAG , "count = " + count +  "is preference" + (adapter.getItem(0) instanceof Preference));
			
			if (null != preferenceScreen1){
				for (int i = 0 ; i < count ; i++){
					preferenceScreen1.addPreference((Preference) adapter.getItem(i));
				}
			}
			
			
		}
XMl:<pre name="code" class="html"><?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:title="preference  root"
    android:summary="preference root summary"
     >

    <Preference
        android:order="1"
        android:key="preference0"
        android:summary="preference0"
        android:title="preference" 
        android:icon="@drawable/ic_launcher"
        >
    </Preference>
    
    <PreferenceScreen 
        android:title="preference  inside"
        android:summary="preference  inside summary"
        android:key="preference screen 0">
        
        <Preference
            android:key="preference3"
            android:order="2"
            android:summary="preference3"
            android:title="preference3" >
        </Preference>
        
        <Preference
            android:key="preference4"
            android:order="2"
            android:summary="preference4"
            android:title="preference4" >
        </Preference>
        
         <CheckBoxPreference
            android:key="preference4"
            android:order="2"
            android:summary="preference4"
            android:title="preference4" >
        </CheckBoxPreference>
        
    </PreferenceScreen>
    
    <PreferenceScreen 
        android:title="preference  inside 1"
        android:summary="preference  inside summary 1"
        android:key="preference screen 1">
    </PreferenceScreen>
    
     <Preference
        android:order="2"
        android:key="preference1"
        android:summary="preference1"
        android:dependency="preference0"
        android:title="preference1" >
    </Preference>

</PreferenceScreen>
结果:
 


都加入进来了,但是排列刚刚相反?  这是为什么呢?

原来是 不每一个都设置了order,并且order的值都是2

为了研究这个问题,把xml改一下 ,如下:

<PreferenceScreen 
        android:title="preference  inside"
        android:summary="preference  inside summary"
        android:key="preference screen 0">
        
        <Preference
            android:key="preference3"
            android:order="2"
            android:summary="preference3"
            android:title="preference3" >
        </Preference>
        
        <Preference
            android:key="preference4"
            android:order="2"
            android:summary="preference4"
            android:title="preference4" >
        </Preference>
        
         <CheckBoxPreference
             android:order="2"
            android:key="preference5"
            android:summary="preference5"
            android:title="preference5" >
        </CheckBoxPreference>
        
    </PreferenceScreen>
    
    <PreferenceScreen 
        android:title="preference  inside 1"
        android:summary="preference  inside summary 1"
        android:key="preference screen 1">
    </PreferenceScreen>

都不加order的话那么显示结果都是  3 4 5 ,都是采用默认的排序,谁写在前面就排在前面

而当设置了order  并且都相同的时候,那么就根order来排序了

在代码中加入打印调试:

if (null != preferenceScreen1){
				for (int i = 0 ; i < count ; i++){
					Log.i(TAG , "key " + ((Preference) adapter.getItem(i)).getKey());
					preferenceScreen1.addPreference((Preference) adapter.getItem(i));
				}
			}
打印结果是  " 5   4  3"	
然后在<span style="font-family: Tahoma, Arial;">preferenceScreen1 在</span>add的时候 是前插的  也就变成了 3  4  5
而<span style="font-family: Tahoma, Arial;">preferenceScreen0 add的时候 也就是 3 4 5  的顺序,被前插也就成了 5 4 3 </span>


<think>好的,我现在需要详细解释Android中PreferencePreferenceScreen的用法。首先,我得回忆一下这两个类的基本作用,它们都属于Android的偏好设置框架,用于构建设置界面。 Preference应该是单个设置的基类,比如CheckBoxPreference、EditTextPreference这些具体子类,每个都代表一种类型的设置项。而PreferenceScreen可能是一个容器,用来组织多个Preference,可能是根布局,或者嵌套在里面的屏幕。 接下来,我得考虑如何组织内容。用户需要详细的使用方法,所以应该分步骤讲解,包括如何创建XML文件,如何添加各种Preference,以及PreferenceScreen的嵌套使用。可能还需要提到监听事件和动态添加Preference的方法。 记得系统级指令里提到,行内公式用$...$,独立公式用$$...$$,但这里可能不太涉及数学公式,不过代码块需要正确展示。另外用中文回答,结构清晰,分点说明。 需要确认是否正确区分PreferencePreferenceScreen的关系。例如,PreferenceScreen可以作为根元素,也可以包含其他PreferenceScreen来创建分层结构。每个Preference的XML属性可能有所不同,比如key、title、summary等。 可能还要提到在Activity中使用PreferenceFragmentCompat,因为现在推荐使用AndroidX库,特别是支持库中的组件。需要说明如何继承并加载XML资源。 另外,动态添加的部分,比如在代码中通过findPreference获取PreferenceScreen对象,然后使用addPreference方法动态添加。这里需要注意正确的方法调用和可能的错误处理。 监听器方面,比如OnPreferenceChangeListener和OnPreferenceClickListener,要说明如何设置和处理回调。 可能还需要提到一些常用的子类,如ListPreference、SwitchPreference等,并给出简单示例。 最后,要确保所有代码示例的语法正确,符合LaTeX要求,但这里的代码是XML和Java/Kotlin,所以应该用代码块包裹,而不是LaTeX公式。不过系统指令可能希望所有技术内容正确,比如代码缩进和标签闭合。 检查是否有遗漏点,比如样式定制、存储机制(SharedPreferences)的关联,或者是否需要提到新的Jetpack Preference库的用法,因为旧的方法可能已经过时。比如,现在推荐使用PreferenceFragmentCompat,并且需要依赖androidx.preference库。 总结步骤可能包括: 1. 添加依赖 2. 创建Preference XML文件 3. 创建PreferenceFragmentCompat子类 4. 在Activity中加载Fragment 5. 各种Preference的配置 6. PreferenceScreen的嵌套使用 7. 动态添加和事件监听 8. 数据存储和获取 需要注意避免错误,比如Preference的key与SharedPreferences中存储的键对应,以及正确设置默认值。 可能用户还希望知道如何读取和写入这些设置,所以简要提及SharedPreferences的获取方法,如PreferenceManager.getDefaultSharedPreferences(context)。 现在需要将这些内容组织成结构清晰的中文回答,分点说明,确保每个部分都准确无误,并符合用户的提问要求。</think>在 Android 开发中,`Preference` 和 `PreferenceScreen` 是用于构建**设置界面**的核心组件,基于 `SharedPreferences` 实现数据存储。以下是详细用法说明: --- ### 一、基础概念 1. **Preference** - 表示单个设置项,如开关、输入框等。 - 常用子类: - `CheckBoxPreference`(复选框) - `EditTextPreference`(输入框) - `ListPreference`(下拉列表) - `SwitchPreference`(开关) - `PreferenceCategory`(分组容器) 2. **PreferenceScreen** - 定义设置界面的根容器,支持嵌套其他 `PreferenceScreen` 实现分层跳转。 - 通过 XML 文件组织布局结构。 --- ### 二、XML 文件配置 1. **创建 XML 文件** 在 `res/xml/` 目录下新建 `preferences.xml`,示例如下: ```xml <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 分组 --> <PreferenceCategory android:title="通用设置"> <SwitchPreference android:key="notifications" android:title="启用通知" android:defaultValue="true" /> <EditTextPreference android:key="username" android:title="用户名" android:dialogTitle="输入用户名" /> </PreferenceCategory> <!-- 嵌套子屏幕 --> <PreferenceScreen android:key="advanced_settings" android:title="高级设置"> <CheckBoxPreference android:key="debug_mode" android:title="调试模式" /> </PreferenceScreen> </PreferenceScreen> ``` --- ### 三、代码中加载 Preference 1. **使用 PreferenceFragmentCompat** - 依赖库:`androidx.preference:preference-ktx:1.2.0`(Java 或 Kotlin) - 创建 Fragment 并加载 XML: ```kotlin class SettingsFragment : PreferenceFragmentCompat() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.preferences, rootKey) } } ``` 2. **在 Activity 中绑定 Fragment** ```kotlin class SettingsActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) supportFragmentManager .beginTransaction() .replace(android.R.id.content, SettingsFragment()) .commit() } } ``` --- ### 四、Preference 事件监听 1. **点击事件** ```kotlin val pref = findPreference<Preference>("username") pref?.setOnPreferenceClickListener { // 处理点击逻辑 true } ``` 2. **值变更监听** ```kotlin val switchPref = findPreference<SwitchPreference>("notifications") switchPref?.setOnPreferenceChangeListener { _, newValue -> val isChecked = newValue as Boolean // 处理开关状态变化 true } ``` --- ### 五、动态添加 Preference 通过代码动态生成设置项: ```kotlin override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { val context = preferenceManager.context val screen = preferenceManager.createPreferenceScreen(context) // 动态添加 SwitchPreference val dynamicSwitch = SwitchPreference(context).apply { key = "dynamic_switch" title = "动态开关" } screen.addPreference(dynamicSwitch) preferenceScreen = screen } ``` --- ### 六、数据存取 通过 `SharedPreferences` 直接读写设置项: ```kotlin val prefs = PreferenceManager.getDefaultSharedPreferences(context) val username = prefs.getString("username", "default_user") prefs.edit().putBoolean("notifications", false).apply() ``` --- ### 七、最佳实践 1. **Key 命名**:使用常量定义 key,避免硬编码。 2. **默认值**:始终通过 `android:defaultValue` 或代码设置默认值。 3. **嵌套层级**:避免超过 2 层 `PreferenceScreen`,防止用户体验复杂化。 通过以上步骤,你可以高效构建符合 Material Design 规范的设置界面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值