一个简单的组合控件示例

来源:互联网 发布:手电筒软件哪个好 编辑:程序博客网 时间:2024/05/22 10:38

前言

  1. 我们要写一个自定义组合控件,放在MainActivity中,MainActivity的布局文件是Android Studio自动生成,名字是activity_main.xml
  2. 我们要写的自定义组合控件由3个TextView组成(叫它们 num1,num2, num3 吧),分别显示三个数字。 规律是 num1显示 a,mum2和num3 就显示 (a+1)和(a+2)。
  3. 根据需求,我们需要给自定义控件增加一个自定义属性:startNum。它代表了num1显示的数字。

步骤:

  • 在values下面新建一个名叫attrs(这个随意)的XML;一个declare-styleable标签被称作一个TypeArray,每个declare-styleable标签可以包含多个attr子标签。
    attr的写法是 一个name,一个format。 比如”
<resources>    <declare-styleable name="texts">       <attr name="startNum" format="integer"/>    </declare-styleable></resources>

format类型参考链接:http://blog.csdn.net/lincyang/article/details/7421757

  • 新建一个XML作为布局文件,这里我们取名my_customed_view.xml. 以LinearLayout包裹,所以等会儿的组合控件也必须继承自LinearLayout ,在这里写好组合控件的样子。
  • 新建一个JAVA类:MyCustomedView,名称随意。继承自LinearLayout。这时候android studio会提示你实现构造方法,选择自动实现之;
  • 在出来的4个方法中,第一个方法只适用于代码创建。我们在XML中定义的自定义控件需要从AttributeSet这个类中读取属性。先放一下这里。
  • 我们重新回到布局文件中, 在 activity_main.xml中写下(怎么布局自己定,我为了简单,就放了这么一个组合控件):
<com.huang.android.customedview1.MyCustomedViewtexts:startNum = "5"android:layout_width="wrap_content"android:layout_height="wrap_content"/>

这时Android Studio会报错,提示不知道 texts:startNum是个啥。别急,在activity_main.xml根布局元素里面增加也一句:

xmlns:my_name_space = "http://schemas.android.com/apk/res-auto"

my_name_space可以随便写,等号后面的不能改。Gradle现在已经可以实现自动查找对应的TypeArray和属性了,找不到编译通不过的。

  • MyCustomedView中,我们在……比如public MyCustomedView(Context context, AttributeSet attrs)这个方法中,定义一个
private int startNum;private TypedArray ta;private Context mContext;private TextView num1;private TextView num2;private TextView num3;

于此同时,我们看到构造方法中的 AttributeSet attrs``这个参数。Context提供了 一系列`obtainStyledAttributes`的重载从attr对象中提取出调用者填写的属性。
这里我们简单点儿:
ta = mContext.obtainStyledAttributes(attrs,R.styleable.texts);“`
此时ta中保存的就是我们之前定义在attrs.xml中的 ,名为texts的 declare-styleable标签…….下的attr子标签了 (不信你可以Toast一下它的长度)。

  • 接下来还有两步必须:
    • 调用LayoutInflater绘制
      ViewLayoutInflater.from(mContext).inflate(R.layout.my_customed_view,this); //注意这个this
    • 取出我们想要的属性:
      int startNum = ta.getInteger(R.styleable.texts_startNum,4);
      //我们的属性是startNum.
      //Android Studio自动在它前面加上texts_来表明它是texts下的startNum属性,避免冲突。
  • 收工,拿到属性想怎么处理都是你的事情了。

附上代码:
MainActivity的布局文件:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:my_name_space = "http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.huang.android.customedview1.MainActivity">    <com.huang.android.customedview1.MyCustomedView        my_name_space:startNum = "5"        android:layout_width="match_parent"        android:layout_height="wrap_content"         /></RelativeLayout>

MyCustomedView自定义组合控件类

public class MyCustomedView extends LinearLayout {    private int startNum;    private TypedArray ta;    private Context mContext;    private TextView num1;    private TextView num2;    private TextView num3;    public MyCustomedView(Context context) {        super(context);        mContext = context;    }    public MyCustomedView(Context context, AttributeSet attrs) {        super(context, attrs);        mContext = context;        ta = mContext.obtainStyledAttributes(attrs,R.styleable.texts);        Toast.makeText(mContext,"length == "+ta.length(),Toast.LENGTH_LONG).show();        initViews();    }    public MyCustomedView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mContext = context;        initViews();    }    public MyCustomedView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);        mContext = context;        initViews();    }    private void initViews()    {        LayoutInflater.from(mContext).inflate(R.layout.my_customed_view,this);        num1 =(TextView) findViewById(R.id.TV_num1);        num2 =(TextView) findViewById(R.id.TV_num2);        num3 =(TextView) findViewById(R.id.TV_num3);        startNum = ta.getInteger(R.styleable.texts_startNum,4);        num1.setText(startNum+"");        num2.setText( (startNum+1)+"");        num3.setText( (startNum+2)+"");    }}

MyCustomedView布局文件:

<?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">    <TextView        android:id="@+id/TV_num1"        android:layout_weight="1"        android:layout_width="0dp"        android:gravity="center_horizontal"        android:layout_height="wrap_content"        android:textSize="30sp"        android:text="1"      />    <TextView        android:layout_weight="1"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:text="2"        android:gravity="center_horizontal"        android:textSize="30sp"        android:id="@+id/TV_num2"/>    <TextView        android:text="3"        android:layout_weight="1"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:gravity="center_horizontal"        android:textSize="30sp"        android:id="@+id/TV_num3" /></LinearLayout>

Values目录下的attrs.xml

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="texts">       <attr name="startNum" format="integer"/>    </declare-styleable></resources>
0 0