Android自带的Preference是这样的布局:一个标题(title)和一个概括(summary)。
现在的需求是:除了一个标题和一个概括之外,还要在Preference的右下角加一个当前值(statusvalues)。
以前,遇到这个状况,都是自己仿照preference.xml文件,在此文件中添加一个TextView在原来布局的下方。如下:
preference_with_value.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
......
android:paddingRight="?android:attr/scrollbarSize" >
<ImageView
android:id="@+android:id/icon"
......
android:layout_gravity="center" />
<RelativeLayout
......
android:layout_weight="1" >
<TextView
android:id="@+android:id/title"
.......
android:textColor="#FF00FFFF" />
<TextView
android:id="@+android:id/summary"
......
android:textColor="#FFFFFF00" />
<!-- 以下的TextView就是我们自己添加的,用来显示statusvalues-->
<TextView
android:id="@+:id/statusvalues"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@android:id/summary"
android:layout_below="@android:id/summary"
android:maxLines="1"
android:textAppearance="@android:style/TextAppearance.Small"
android:textColor="#FFFFFF00" />
<!-- 以上的TextView就是我们自己添加的,用来显示statusvalues-->
</RelativeLayout>
<LinearLayout
android:id="@+android:id/widget_frame"
.......
android:orientation="vertical" />
</LinearLayout>
然后再设置preference的layout属性,调用自己定义的布局。如下:
<Preference
android:key="child__preference"
<!-- 使用我们自己的布局 -->
android:layout="@layout/preference_with_value"
android:summary="summary_child_preference"
android:title="title_child_preference" />
</Preference>
然后再到代码里findPreference的时候,findViewById(R.id.statusvalues),接着再设置textView.setText();
。。。。。
可以看到这么做真的比较烦。并且,每次用到这样的preference,都要这么重写一遍,各种蛋疼(也叫卵子痛)。
现在在做framework,我们就可以随便修改系统代码,来提供这样的布局给上层app调用。不是吗?这样,就不需要到处声明layout,到处findViewById了。
愿望很美好~~问题来了,如何做呢?
首先,要知道我们的目标:参照android原生的设计:肯定是要提供一个类似于title和summary的属性,给上层app调用。同时,在java文件中,提供类似于setTitle和setSummary的方法。
然后就是实现了。如何在framework中添加自己的set方法?这个不难。找到Preference.java,仿照setTitle方法,添加setStatusValues()。实现基本相同,就是把id改一下。这里简单的贴出部分伪代码:
packages com.android.view;
......
public class Preference ....
{
......
Charsequence mTitle;
//下面就是我们仿照title的statusValues
Charsequence mStatusValues;
......
public Charsequence getTitle(){
......
}
public void setTitle(Charsequence title){
......
}
public void setTitle(int resId){
......
}
//下面就是我们仿照的title的statusvalues
public Charsequence getStatusValues(){
return mStatusValues;
}
public void setStatusValues(Charsequence value){
//......就不实现了,title的实现体,换个变量名而已
}
public void setStatusValues(int resId){
//......就不实现了,title的实现体,换个变量名而已
}
.......
protected void onBindView(View view) {
final TextView titleView = (TextView) view.findViewById(
com.android.internal.R.id.title);
if (titleView != null) {
final CharSequence title = getTitle();
if (!TextUtils.isEmpty(title)) {
titleView.setText(title);
titleView.setVisibility(View.VISIBLE);
} else {
titleView.setVisibility(View.GONE);
}
}
......
//下面就是我们仿照的title的statusvalues
final TextView statusView = (TextView) view.findViewById(
com.android.internal.R.id.statusvalue);
if (statusView != null) {
final CharSequence statusvalue = getStatusValue();
if (!TextUtils.isEmpty(statusvalue)) {
statusView.setText(statusvalue);
statusView.setVisibility(View.VISIBLE);
} else {
statusView.setVisibility(View.GONE);
}
}
}
......
}
还需要在一个地方修改布局:preference.xml(在frameworks/base/core/res/res/layout/中)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingRight="?android:attr/scrollbarSize" >
<ImageView
android:id="@+android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="6dip"
android:layout_marginLeft="15dip"
android:layout_marginRight="6dip"
android:layout_marginTop="6dip"
android:layout_weight="1" >
<TextView
android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="@android:style/TextAppearance.Medium"
android:textColor="#FF00FFFF" />
<TextView
android:id="@+android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@android:id/title"
android:layout_below="@android:id/title"
android:maxLines="4"
android:textAppearance="@android:style/TextAppearance.Small"
android:textColor="#FFFFFF00" />
<!-- 以下的TextView就是我们自己添加的,用来显示statusvalues-->
<TextView
android:id="@+:id/statusvalues"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@android:id/summary"
android:layout_below="@android:id/summary"
android:maxLines="1"
android:textAppearance="@android:style/TextAppearance.Small"
android:textColor="#FFFFFF00" />
<!-- 以上的TextView就是我们自己添加的,用来显示statusvalues-->
</RelativeLayout>
<LinearLayout
android:id="@+android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical" />
</LinearLayout>
在bindView的时候,注意到添加了这样一个com.android.internal.R.id.statusvalue这样一个id。这也是关键的地方。
参考title和summary的id的定义。可以发现,我们需要在2个地方添加属性。分别是:
attrs.xml和public.xml。(均在frameworks/base/core/res/res/values/中)
attrs.xml中,添加的是preference的属性,表明preference具有statusvalue这样的属性。 如下:
<declare-styleable name="Preference">
......
<!--这是我们添加的属性 <declare-styleable name="Preference"> 中哦-->
<attr name="statusvalue" format="string"/>
<!--这是我们添加的属性 <declare-styleable name="Preference"> 中哦-->
</declare-styleable>
public.xml中,在最后添加如下属性。
<java-symbol type="id" name="statusvalue" />
<resources>
。。。。。。
<!--我们添加的 -->
<java-symbol type="id" name="statusvalue" />
<public type="attr" name="statusvalue" />
<!--我们添加的 -->
</resources>
这里我们添加了2个属性。
java-symbol type="id" name="statusvalue"
这个id就是上面的layout中,我们添加的id。用来给Preference.java文件获取view。
<public type="attr" name="statusvalue" />
这个public,用来公开statusvalue,这样就可以在xml中,使用android:statusvalue这样的属性了。
好了。我们编译源代码。就可以使用我们自己添加的属性拉!!
总结一下:
如果添加自己的属性,需要在以下几处修改:
1.public.xml中,申明id,暴露attr。
2.attrs.xml中,声明attr。
3.layout文件中,新加布局,使用上面的id和attr。
4.java文件中,增加对attr和新加布局的解析。