欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中Fragmen首选项使用自定义的ListPreference的方法

程序员文章站 2024-03-31 17:15:22
首选项这个名词对于熟悉android的朋友们一定不会感到陌生,它经常用来设置软件的运行参数。 android提供了一种健壮并且灵活的框架来处理首选项。它提供了简单的api...

首选项这个名词对于熟悉android的朋友们一定不会感到陌生,它经常用来设置软件的运行参数。
android提供了一种健壮并且灵活的框架来处理首选项。它提供了简单的api来隐藏首选项的读取和持久化,并且提供了一个优雅的首选项界面。
几种常见的首选项:
(1)checkboxpreference:用来打开或关闭某个功能
(2)listpreference:用来从多个选项中选择一个值;
(3)edittextpreference:用来配置一段文字信息;
(4)preference:用来执行相关的自定义操作(上图中的清除缓存、历史记录、表单、cookie都属于此项);
(5)ringtonepreference:专门用来为用户设置铃声。
当我们使用首选项框架时,用户每更改一项的值后,系统就会立即在/data/data/[package_name]/shared_prefs下生成一个[package_name]_preferences.xml的文件,文件会记录最新的配置信息。
那么本文要讲的就是其中的listpreference,以及通过preferencefragment来使用自定义的listpreference。

1. 自定义属性
添加文件res/values/attrs.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="iconlistpreference">
  <attr name="entryicons" format="reference" />
 </declare-styleable>
</resources>

说明:
(01) name="iconlistpreference",与自定义的listpreference类的名称相对应。后面会实现一个继承于listpreference的iconlistpreference.java。
(02) name="entryicons",这是属性的名称。
(03) format="reference",这描述属性的值是引用类型。因为,后面会根据资源id设置该属性,所以将属性格式设为reference。如果是颜色,设为format="color";如果是布尔类型,format="boolean";如果是字符串,设为format="string"。
2. 自定义listpreference
2.1 构造函数

public iconlistpreference(context context, attributeset attrs) {
 super(context, attrs);
 mcontext = context;

 // 获取自定义的属性(attrs.xml中)对应行的typedarray
 typedarray a = context.obtainstyledattributes(attrs, r.styleable.iconlistpreference);
 // 获取entryicons属性对应的值
 int iconresid = a.getresourceid(r.styleable.iconlistpreference_entryicons, -1);
 if (iconresid != -1) {
  setentryicons(iconresid);
 } 

 // 获取preferece对应的key
 mkey = getkey();
 // 获取sharedpreferences
 mpref = preferencemanager.getdefaultsharedpreferences(context);
 // 获取sharedpreferences.editor
 meditor = mpref.edit();
 // 获取entry
 // 注意:如果配置文件中没有android:entries属性,则getentries()为空;
 mentries = getentries();
 // 获取entry对应的值
 // 注意:如果配置文件中没有android:entryvalues属性,则getentries()为空
 mentryvalues = getentryvalues();

 // 获取该listpreference保存的值
 string value = mpref.getstring(mkey, "");
 mposition = findindexofvalue(value);
 // 设置summary
 if (mposition!=-1) {
  setsummary(mentries[mposition]);
  seticon(mentryicons[mposition]);
 } 

 a.recycle();
}

说明:
(01) 首先,根据obtainstyledattributes()能获取自定义属性对应的typedarray对象。
(02) 在自定义属性中,entryicons对应的类名是iconlistpreference。因为需要通过"类名"_"属性名",即iconlistpreference_entryicons的方式来获取资源信息。
(03) getkey()是获取preferece对应的key。该key是preference对象的唯一标识。
(04) getentries()是获取preferece的entry数组。
(05) getentryvalues()是获取preferece的entry对应的值的数组。
(06) setsummary()是设置preferece的summary标题内容。
(07) seticon()是设置preferece的图标。
2.2 自定义listpreference中图片相关代码

/**
 * 设置图标:icons数组
 */
private void setentryicons(int[] entryicons) {
 mentryicons = entryicons;
}

/**
 * 设置图标:根据icon的id数组
 */
public void setentryicons(int entryiconsresid) {
 typedarray icons = getcontext().getresources().obtaintypedarray(entryiconsresid);
 int[] ids = new int[icons.length()];
 for (int i = 0; i < icons.length(); i++)
  ids[i] = icons.getresourceid(i, -1);
 setentryicons(ids);
 icons.recycle();
}

说明:这两个函数是读取图片信息的。
2.3 自定义listpreference弹出的列表选项

@override
protected void onpreparedialogbuilder(builder builder) {
 super.onpreparedialogbuilder(builder);

 iconadapter adapter = new iconadapter(mcontext);
 builder.setadapter(adapter, null);
}

说明:点击listpreference,会弹出一个列表对话框。通过重写onpreparedialogbuilder(),我们可以自定义弹出的列表对话框。这里是通过iconadapter来显示的。

public class iconadapter extends baseadapter{

 private layoutinflater minflater;


 public iconadapter(context context){
  this.minflater = layoutinflater.from(context);
 }
 @override
 public int getcount() {
  return mentryicons.length;
 }

 @override
 public object getitem(int arg0) {
  return null;
 }

 @override
 public long getitemid(int arg0) {
  return 0;
 }

 @override
 public view getview(int position, view convertview, viewgroup parent) {

  viewholder holder = null;
  if (convertview == null) {

   holder = new viewholder();

   convertview = minflater.inflate(r.layout.icon_adapter, parent, false);
   holder.layout = (linearlayout)convertview.findviewbyid(r.id.icon_layout);
   holder.img = (imageview)convertview.findviewbyid(r.id.icon_img);
   holder.info = (textview)convertview.findviewbyid(r.id.icon_info);
   holder.check = (radiobutton)convertview.findviewbyid(r.id.icon_check);
   convertview.settag(holder);

  }else {
   holder = (viewholder)convertview.gettag();
  }

  holder.img.setbackgroundresource(mentryicons[position]);
  holder.info.settext(mentries[position]);
  holder.check.setchecked(mposition == position);

  final viewholder fholder = holder;
  final int fpos = position;
  convertview.setonclicklistener(new view.onclicklistener() {

   @override
   public void onclick(view v) {
    v.requestfocus();
    // 选中效果
    fholder.layout.setbackgroundcolor(color.cyan);

    // 更新mposition
    mposition = fpos;
    // 更新summary
    iconlistpreference.this.setsummary(mentries[fpos]);
    iconlistpreference.this.seticon(mentryicons[fpos]);
    // 更新该listpreference保存的值
    meditor.putstring(mkey, mentryvalues[fpos].tostring());
    meditor.commit();

    // 取消listpreference设置对话框
    getdialog().dismiss();
   }
  });

  return convertview;
 }

 // listpreference每一项对应的layout文件的结构体
 private final class viewholder {
  imageview img;
  textview info;
  radiobutton check;
  linearlayout layout;
 }
}

说明:弹出的列表对话框中的每一项的内容是通过布局icon_adapter.xml来显示的。下面看看icon_adapter.xml的源码。

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/icon_layout" 
 android:orientation="horizontal"
 android:paddingleft="6dp" 
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">


 <imageview
  android:id="@+id/icon_img" 
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" 
  android:gravity="center_vertical"
  android:layout_margin="4dp"/>

 <textview
  android:id="@+id/icon_info" 
  android:layout_width="0dp"
  android:layout_height="wrap_content" 
  android:layout_weight="1"
  android:paddingleft="6dp"
  android:layout_gravity="left|center_vertical"
  android:textappearance="?android:attr/textappearancelarge" />

 <radiobutton
  android:id="@+id/icon_check"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:checked="false"
  android:layout_gravity="right|center_vertical"
  android:layout_marginright="6dp"/>

</linearlayout>

至此,自定义的listpreference就算完成了。下面就是如何使用它了。
3. 使用该自定义listpreference
我们是通过preferencefragment使用该自定义的listpreference。
3.1 preferencefragment的配置文件
res/xml/preferences.xml的内容如下:

<preferencescreen xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:iconlistpreference="http://schemas.android.com/apk/res/com.skw.fragmenttest">

 <!-- 系统默认的listpreference -->
 <preferencecategory
  android:title="preferencecategory a">

  <!-- 
   (01) android:key是preferece的id
   (02) android:title是preferece的大标题
   (03) android:summary是preferece的小标题
   (04) android:dialogtitle是对话框的标题
   (05) android:defaultvalue是默认值
   (06) android:entries是列表中各项的说明
   (07) android:entryvalues是列表中各项的值
   -->
  <listpreference 
   android:key="list_preference" 
   android:dialogtitle="choose font" 
   android:entries="@array/pref_font_types" 
   android:entryvalues="@array/pref_font_types_values" 
   android:summary="sans" 
   android:title="font" 
   android:defaultvalue="sans"/> 
 </preferencecategory>

 <!-- 自定义的listpreference -->

 <preferencecategory
  android:title="preferencecategory b">

  <!-- 
   iconlistpreference:entryicons是自定义的属性
   -->
  <com.skw.fragmenttest.iconlistpreference
   android:key="icon_list_preference" 
   android:dialogtitle="chooseicon" 
   android:entries="@array/android_versions"
   android:entryvalues="@array/android_version_values" 
   iconlistpreference:entryicons="@array/android_version_icons"
   android:icon="@drawable/cupcake"
   android:summary="summary_icon_list_preference"
   android:title="title_icon_list_preference" /> 

 </preferencecategory>

</preferencescreen>

说明:该配置文件中使用了"系统默认的listpreference"和"自定义的listpreference(即iconlistpreference)"。
注意,iconlistpreference中的"iconlistpreference:entryicons"属性。前面的"iconlistpreference"与该文件的命名空间表示"xmlns:iconlistpreference="http://schemas.android.com/apk/res/com.skw.fragmenttest"中的iconlistpreference一样! 而entryicons则是我们自定义的属性名称。
3.2 自定义preferencefragment的代码

public class prefsfragment extends preferencefragment {

 @override
 public void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);

  addpreferencesfromresource(r.xml.preferences);
 }

 ...
}

4. 使用prefsfragment
下面,就可以在activity中使用该prefsfragment了。
4.1 使用prefsfragment的activity的代码

public class fragmenttest extends activity {

 @override
 public void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.main);

  // 获取fragmentmanager
  fragmentmanager fragmentmanager = getfragmentmanager();
  // 获取fragmenttransaction  
  fragmenttransaction fragmenttransaction = fragmentmanager.begintransaction();

  prefsfragment fragment = new prefsfragment();
  // 将fragment添加到容器frag_example中
  fragmenttransaction.add(r.id.prefs, fragment);
  fragmenttransaction.commit();
 } 
}

4.2 使用prefsfragment的activity的配置文件
res/layout/main.xml的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 >

 <framelayout
  android:id="@+id/prefs"
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>

</linearlayout>