自定义控件布局给APP调用

最近在做系统时,遇到一个需求:
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和新加布局的解析。

转载于:https://my.oschina.net/lifj/blog/133340

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值