PreferenceFragment详解

【正文】

一、PreferenceFragment的引入:

PreferenceActivity是一个非常有用的基类,当我们开发Android项目时避免不了选项设置,这些设置习惯用Preference来保存。Android专门为这种Activity提供了便捷的基类PreferenceActivity。如果继承自Preference则不需要自己控制Preference的读写,PreferenceActivity会为我们处理一切。

PreferenceActivity与普通的Activity不同,它不是使用界面布局文件,而是使用选项设置的布局文件

选项设置布局文件以PreferenceScreen作为根元素来表示定义一个参数设置界面布局。

从Android 3.0以后官方不再推荐直接让PreferenceActivity加载选项设置布局文件,而是建议使用PreferenceFragment,二者用法类似。所以今天就来学习一下。

下面的这张截图就是一个典型的例子:

我们会看到整个页面被分为几组:无线和网络、个人、账户、设备、系统。这个分组(或者叫分类)就是PreferenceCategory。

Wifi右边有开关,这一项就是CheckBoxPreference;其他还有ListPreference和EditTextPreference。

你的每一次设置,都会被Preference自动保存下来,这就是setting的数据持久化。每个Preference都是以键值对的形式保存下来的。

PreferenceActivity的继承关系图:(不推荐使用)

PreferenceFragment的继承关系图:(推荐使用)

二、在XML文件中Preference的种类:

根节点中一定是<PreferenceScreen> 元素,在这个元素中可以添加不同的Preference。常见的Preference控件有:

直接子类:DialogPreference, PreferenceGroup, RingtonePreference, TwoStatePreference 非直接子类: CheckBoxPreference ,  EditTextPreference ListPreference , MultiSelectListPreference, PreferenceCategory, PreferenceScreen, SwitchPreference

我们还是通过实际的例子来实现吧。 

【实例】

先新建一个工程文件:

新建类PrefFragment.java,让其继承PreferenceFragment,并加载选项设置的布局文件:(核心代码是第6行和13行)

01. 1 package com.example.m05_preffragment01;
02. 2
03. 3 import android.os.Bundle;
04. 4 import android.preference.PreferenceFragment;
05. 5
06. <strong> 6 public class PrefFragment extends PreferenceFragment {
07. </strong> 7     @Override
08. 8     public void onCreate(Bundle savedInstanceState) {
09. 9         // TODO Auto-generated method stub
10. 10         super.onCreate(savedInstanceState);
11. 11        
12. <strong>12         //从xml文件加载选项
13. 13         addPreferencesFromResource(R.xml.preferences);
14. </strong>14     }
15. 15 }

然后,在MainActivity.java中加载上面的Fragment:

01. 1 package com.example.m05_preffragment01;
02. 2
03. 3 import android.app.Activity;
04. 4 import android.app.FragmentManager;
05. 5 import android.app.FragmentTransaction;
06. 6 import android.os.Bundle;
07. 7
08. 8 public class MainActivity extends Activity {
09. 9
10. 10     @Override
11. 11     protected void onCreate(Bundle savedInstanceState) {
12. 12         super.onCreate(savedInstanceState);
13. 13         setContentView(R.layout.activity_main);
14. 14        
15. 15         //加载PrefFragment
16. 16         FragmentManager fragmentManager = getFragmentManager();
17. 17         FragmentTransaction transaction = fragmentManager.beginTransaction();
18. 18         PrefFragment prefFragment = new PrefFragment();
19. 19         transaction.add(R.id.prefFragment, prefFragment);
20. 20         transaction.commit();
21. 21        
22. 22     }
23. 23    
24. 24 }

接下来的知识就是重头戏了,既然PrefFragment要加载选项设置的布局文件R.xml.preferences,那我们就来定义一下这个preferences.xml

在res目录下新建立一个xml目录,在该目录中新建文件preferences.xml:

关于preferences.xml的文件里面的代码,请看下面这一段。

五、preference详解:

1、<PreferenceCategory>的方式进行分组:

preferences.xml举例如下:

01. <?xml version='1.0' encoding='utf-8'?>
02. <PreferenceScreen xmlns:android='http://schemas.android.com/apk/res/android' >
03.  
04. <!-- 设置的类别 -->
05. <PreferenceCategory
06. android:key='mylocation'
07. android:summary='我的位置'
08. android:title='我的位置源'>             
09. <CheckBoxPreference
10. android:key='wireless_network'
11. android:summary='使用<a href="http://www.it165.net/network/nwwx/" target="_blank" class="keylink">无线网络</a>查看应用程序中的位置'
12. android:title='使用<a href="http://www.it165.net/network/nwwx/" target="_blank" class="keylink">无线网络</a>'/>         
13. </PreferenceCategory>
14.  
15. <PreferenceCategory
16. android:key='mymsg'
17. android:summary='个人信息'
18. android:title='个人信息'>             
19. <EditTextPreference
20. android:key='myname'
21. android:title='请输入真实姓名'
22. android:summary='姓名'/>         
23. </PreferenceCategory>   
24.  
25. </PreferenceScreen>

上方代码中,一个<PreferenceCategory>就是一个类别,单个的<PreferenceCategory>可以放入任意的Preference控件。我们在第一个类别中放入了CheckBoxPreference控件,在第二个类别中放入了EditTextPreference控件。运行效果如下:

运行时候,会自动在/data/data/<packagename>/shared_prefs/目录生成一个文本文件:

注:这个文本的文件名太长了,我们可以在上方PrefFragment.java的第13行代码后面加上这样一句话来修改文件名:(这里我将文件名修改为:mysetting)

1. getPreferenceManager().setSharedPreferencesName('mysetting');

文本内容如下:

我们现在在CheckBoxPreference中打钩,然后在EditTextPreference中输入内容:

文本内容显示如下:

2、显示子屏幕subscreens方式的进行分组:

01. 1 <?xml version='1.0' encoding='UTF-8'?>
02. 2 <PreferenceScreen xmlns:android='http://schemas.android.com/apk/res/android'
03. 3     android:title='Settings' >
04. 4
05. 5     <PreferenceScreen
06. 6         xmlns:android='http://schemas.android.com/apk/res/android'
07. 7         android:summary='settings about emotions'
08. 8         android:title='Emotions' >
09. 9         <CheckBoxPreference
10. 10             android:defaultValue='true'
11. 11             android:summaryOff='No,I am sorry.'
12. 12             android:summaryOn='Yes,I love you!'
13. 13             android:title='Love me?' >
14. 14         </CheckBoxPreference>
15. 15         <CheckBoxPreference
16. 16             android:defaultValue='false'
17. 17             android:summaryOff='No,you are a good person.'
18. 18             android:summaryOn='Yes,I hate you!'
19. 19             android:title='Hate me?' >
20. 20         </CheckBoxPreference>
21. 21     </PreferenceScreen>
22. 22    
23. 23     <PreferenceScreen
24. 24         xmlns:android='http://schemas.android.com/apk/res/android'
25. 25         android:summary='settings about relations'
26. 26         android:title='Relations' >
27. 27         <CheckBoxPreference
28. 28             android:defaultValue='true'
29. 29             android:summaryOff='No,I am sorry.'
30. 30             android:summaryOn='Yes,we are family!'
31. 31             android:title='Family?' >
32. 32         </CheckBoxPreference>
33. 33         <CheckBoxPreference
34. 34             android:defaultValue='false'
35. 35             android:summaryOff='No,I am sorry.'
36. 36             android:summaryOn='Yes,we are friends!'
37. 37             android:title='Friends?' >
38. 38         </CheckBoxPreference>
39. 39     </PreferenceScreen>
40. 40
41. 41 </PreferenceScreen>

运行效果如下:

点击上方第一个preference,进入下图中左侧界面;点击上方第二个preference,进入下图中右侧界面。效果如下:

3、ListPreference控件:

点击该控件后,将列出一个单选按钮的列表。用法如下:

01. <?xml version='1.0' encoding='utf-8'?>
02. <PreferenceScreen xmlns:android='http://schemas.android.com/apk/res/android' >
03.  
04. <PreferenceCategory
05. android:key='mylocation'
06. android:summary='我的位置'
07. android:title='我的位置源'>   
08. <ListPreference
09. android:key='mycities'
10. android:title='所属城市'
11. android:summary='点击弹出城市列表'
12. android:dialogTitle='请选择城市'
13. android:entries='@array/cities'
14. android:entryValues='@array/cities'/>
15. </PreferenceCategory>
16.  
17. </PreferenceScreen>

上方代码中,PreferenceScreen为根标签,ListPreference为子标签。ListPreference的常见属性如下:

android:key 唯一标识符,和android:id相类似,PreferenceManager可以以其为参数通过findPreference获取指定的preference 。 注意,这个android:key的值也是Preference文件里面的XML“键”名 android:title 大标题 android:summary 标题下面的小字(这个要作为选项卡才有) android:entries 弹出的对话框中,列表显示的文本内容,注意哦,这里指定的是一个数组。 android:entryValues 与android:entries相对应的值 android:defaultValue 当对应值不存在时的默认值 android:dialogTitle 弹出的对话框中的标题信息

关于android:entriesandroid:entryValues的区别,要强调一下:

android:entries :The human-readable array to present as a list. 是展现给用户的列表的值。  android:entryValues  :he array to find the value to save for a preference when an entry from entries is selected. 展现的用户的选择列表的每个元素选择后,需要存储到手机中,这里的entryValues就是列表中各个元素被选择后存储到手机中的值(通过sharedPreferences保存在/data/data/<packagename>/shared_prefs/目录下)。简单的说就是此处是数据库中的值。上面的android:entries是展现给用户的列表的值。

我们在上方代码中的第13、14行引用了数据,紧接着我们要在values目录下的strings.xml文件中定义这个被引用的城市列表(即数据来源):

01. 1 <?xml version='1.0' encoding='utf-8'?>
02. 2 <resources>
03. 3
04. 4     <string name='app_name'>m05_PrefFragment01</string>
05. 5     <string name='action_settings'>Settings</string>
06. 6     <string name='hello_world'>Hello world!</string>
07. 7
08. <strong> 8     <string-array name='cities'>
09. 9         <item>成都</item>
10. 10         <item>重庆</item>
11. 11         <item>黄冈</item>
12. 12     </string-array></strong>
13. 13
14. 14 </resources>

上方代码中,8至12行:即加粗部分,是我添加的数据源。

运行程序效果如下:

六、监听事件onPreferenceTreeClick()方法:

1. public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen Preference preference) 

当任何一个preference控件被点击,都将触发该方法。但是可以通过preference.getKey()这个方法找到具体是哪个preference被点击了,因为每个preference的key都是唯一的。

【实例】

现将preferences.xml这个设置选项的布局文件,定义如下:

01. <?xml version='1.0' encoding='utf-8'?>
02. <PreferenceScreen xmlns:android='http://schemas.android.com/apk/res/android' >
03.  
04. <!-- 设置的类别 -->
05. <PreferenceCategory
06. android:key='mylocation'
07. android:summary='我的位置'
08. android:title='我的位置源' >
09. <CheckBoxPreference
10. android:key='wireless_network'
11. android:summary='使用无线网络查看应用程序(例如Google地图)中的位置'
12. android:title='使用无线网络' />
13. <CheckBoxPreference
14. android:key='gps_satellite_setting'
15. android:summary='定位时,精确到街道级别(取消选择可节约电量)'
16. android:title='启用GPS卫星设置' />
17. </PreferenceCategory>
18.  
19. <PreferenceCategory
20. android:key='mymessage'
21. android:summary='个人信息设置'
22. android:title='个人信息设置' >
23. <CheckBoxPreference
24. android:key='yesno_save_individual_info'
25. android:title='是否保存个人信息' />
26. <EditTextPreference
27. android:key='individual_name'
28. android:summary='请输入真实姓名'
29. android:title='姓名 ' />
30. <ListPreference
31. android:entries='@array/cities'
32. android:entryValues='@array/cities'
33. android:key='mycity'
34. android:summary='所属城市'
35. android:title='所属城市' />
36. </PreferenceCategory>
37.  
38. </PreferenceScreen>

运行效果如下:

现在我们需要做的是,选中上方红框中的CheckBoxPreference,对应下面的EditTextPreference为编辑状态;否则,如果CheckBoxPreference没有被选中,则EditTextPreference为不可编辑状态。修改PrefFragment.java的代码,其完整版代码如下:

01. 1 package com.example.m05_preffragment01;
02. 2
03. 3 import android.os.Bundle;
04. 4 import android.preference.CheckBoxPreference;
05. 5 import android.preference.EditTextPreference;
06. 6 import android.preference.Preference;
07. 7 import android.preference.PreferenceFragment;
08. 8 import android.preference.PreferenceScreen;
09. 9
10. 10 public class PrefFragment extends PreferenceFragment {
11. 11
12. 12     @Override
13. 13     public void onCreate(Bundle savedInstanceState) {
14. 14         // TODO Auto-generated method stub
15. 15         super.onCreate(savedInstanceState);
16. 16        
17. 17         //从xml文件加载选项
18. 18         addPreferencesFromResource(R.xml.preferences);
19. 19     }
20. 20    
21. 21     @Override
22. 22     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
23. 23             Preference preference) {
24. 24         //如果“保存个人信息”这个按钮被选中,将进行括号里面的操作
25. 25         if('yesno_save_individual_info'.equals(preference.getKey())) {           
26. 26             CheckBoxPreference checkBoxPreference = (CheckBoxPreference)findPreference('yesno_save_individual_info');
27. 27             EditTextPreference editTextPreference = (EditTextPreference)findPreference('individual_name');
28. 28             //让editTextPreference和checkBoxPreference的状态保持一致
29. 29             editTextPreference.setEnabled(checkBoxPreference.isChecked());
30. 30         }
31. 31         // TODO Auto-generated method stub
32. 32         return super.onPreferenceTreeClick(preferenceScreen, preference);
33. 33     }
34. 34 }

代码解释:

当任何一个preference控件被点击,都将触发onPreferenceTreeClick()方法(22行),但是可以通过preference.getKey()这个方法找到具体是哪个preference被点击(25行)。

26行、27行:通过public Preference findPreference(CharSequence key)找到对应的preference,然后强转为它的子类。

29行:核心代码,让editTextPreference和checkBoxPreference的状态保持一致。

运行效果如下:

这样,我们的功能就实现了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值