自定义控件(继承系统控件,非自绘)

来源:互联网 发布:淘宝网小开衫 编辑:程序博客网 时间:2024/06/17 10:54

1.写一个类继承自已有的控件(比如textview),override其中的构造函数:

public class MyTextView extends TextView {    public MyTextView(Context context) {        super(context);    }    public MyTextView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }}

第一个构造函数一般在代码里new这个自定义控件时使用

第二个构造函数是在layout的xml文件中声明这个控件时,自动调用,attrs里包含了在xml中给这个自定义view设置的所有属性,包括自定义属性和系统属性

第三个构造函数不会自动调用,一般在第二个构造函数手动调用这个构造函数,defStyleAttr是一个自定义属性,在theme文件中利用这个自定义属性给自定义view中的自定义属性设置默认值(详见下面讲解)

第三个构造函数,只有在api21以上才能使用,也不会自动调用,一般在第三个或第二个构造函数手动调用,defStyleRes用于在theme文件中给自定义view中的自定义属性设置默认值(详见下面讲解)


2.在xml中声明这个自定义控件,并设置相关属性


<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.zhouyi.userdefineattrsandstyle.MainActivity">    <com.example.zhouyi.userdefineattrsandstyle.MyTextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Hello World!" /></RelativeLayout>

这时候,可以在其构造函数中获取这些定义的系统属性:

public MyTextView(Context context, AttributeSet attrs) {    super(context, attrs);    TypedArray typedArray = context.obtainStyledAttributes(attrs,            new int[]{android.R.attr.text});    String strValue = typedArray.getString(0);}


obtainStyledAttributes用于在所有属性集合(attrs)中获取我们需要的属性值,第二个参数是一个int数组,里面设置我们需要获取的属性对应的资源id,比如textview的text属性其实是在android的系统资源的属性文件中设置的一个属性


3.使用自定义属性:

首先在res/values底下建立一个attrs.xml文件,指定自定义属性集合的名字,以及里面的属性名和属性格式:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MyTextViewStyle">        <attr name="attr_one" format="string"/>        <attr name="attr_two" format="string" />        <attr name="attr_three" format="string" />        <attr name="attr_four" format="string" />    </declare-styleable></resources>

在xml中定义自定义属性的命名空间并设置自定义属性

<?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:test = "http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.zhouyi.userdefineattrsandstyle.MainActivity">    <com.example.zhouyi.userdefineattrsandstyle.MyTextView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        test:attr_one="attr_one from xml"        android:text="Hello World!" /></RelativeLayout>

自定属性的命名空间名字可以随意,值统一为:http://schemas.android.com/apk/res-auto


在代码中获取自定义属性值:

public MyTextView(Context context, AttributeSet attrs) {    super(context, attrs);    TypedArray typedArray = context.obtainStyledAttributes(attrs,            R.styleable.MyTextViewStyle);    String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one);}

R.styleable.MyTextViewStyle实际上是一个数组,在自动生成的R文件中可以看到:

public static final class attr {    public static final int attr_one=0x7f010000;    public static final int attr_two=0x7f010001;    public static final int attr_three=0x7f010002;    public static final int attr_four=0x7f010003;}

public static final class styleable {    public static final int[] Customize = {        0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003    };    public static final int MyTextView_attr_one = 0;    public static final int MyTextView_attr_two = 1;        public static final int MyTextView_attr_three = 2;    public static final int MyTextView_attr_four = 3;}


4.在哪些地方可以给自定义属性赋值,优先级怎么样:

首先,在布局xml文件中可以给自定义属性赋值,如第3点所示


在样式(style)中也可以给自定义属性赋值

在style.xml中加入一个新的style:

<style name="ThroughStyle">    <item name="attr_one">attr one from style</item>    <item name="attr_two">attr two from style</item></style>

注意name直接设置自定义属性名,不要加前缀

在布局文件中声明控件的style为这个style:

<com.example.zhouyi.userdefineattrsandstyle.MyTextView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    style="@style/ThroughStyle"    android:text="Hello World!" />

获取属性值的代码不变

style中设置的值比布局xml中设置的值优先级低,也就是说如果同时设置,只有布局xml设置的值起作用



还可以在defStyleAttr(参照第三个构造函数)中给自定义属性赋值:

首先在attrs.xml中设置一个自定义属性:

<resources>    <declare-styleable name="MyTextViewStyle">        <attr name="attr_one" format="string"/>        <attr name="attr_two" format="string" />        <attr name="attr_three" format="string" />        <attr name="attr_four" format="string" />    </declare-styleable>        <attr name="MyTextViewStyleRef" format="reference"/></resources>
这个属性不要设置到declare-styleable里面,格式为refrence

然后在style.xml中,找到能影响这个自定义属性的theme,在theme中给这个属性设置值,设置的这个值也是一个自定义style,在这个自定义style中,设置自定义属性的值

<!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">    <!-- Customize your theme here. -->    <item name="colorPrimary">@color/colorPrimary</item>    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>    <item name="colorAccent">@color/colorAccent</item>    <item name="MyTextViewStyleRef">@style/MyTextViewStyleRefValue</item></style><style name="MyTextViewStyleRefValue">    <item name="attr_one">attr one from theme reference</item></style>
获取自定义属性值的代码也要改一下:

public MyTextView(Context context, AttributeSet attrs) {    super(context, attrs);    TypedArray typedArray = context.obtainStyledAttributes(attrs,            R.styleable.MyTextViewStyle,R.attr.MyTextViewStyleRef,0);    String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one);}
obtainStyledAttributes中加入两个参数,后面那个暂时不管(设置为0,表示忽略),前面那个传入用于设置值的自定义属性的资源id

通过defStyleAttr设置的值,优先级比前两个低



还可以通过defStyleRes(参照第四个构造函数)给自定义属性赋值:

首先在styles.xml中定义一个style:

<style name="MyTextViewDefaultStyle">    <item name="attr_one">attr one from default theme</item></style>
在代码中获取自定义属性值:

public MyTextView(Context context, AttributeSet attrs) {    super(context, attrs);    TypedArray typedArray = context.obtainStyledAttributes(attrs,            R.styleable.MyTextViewStyle,0,R.style.MyTextViewDefaultStyle);    String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one);}
defStyleAttr设置为0,表示忽略这个设置

defStyleRes的优先级比布局xml和style低,它和defStyleAttr的关系是:仅在defStyleAttr为0或defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用,否则defStyleRes的设置不起作用

比如既定义了defStyleRes 又指定了defStyleAttr 

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">    <!-- Customize your theme here. -->    <item name="colorPrimary">@color/colorPrimary</item>    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>    <item name="colorAccent">@color/colorAccent</item>    <item name="MyTextViewStyleRef">@style/MyTextViewStyleRefValue</item></style><style name="MyTextViewStyleRefValue">    <item name="attr_two">attr one from theme reference</item></style><style name="MyTextViewDefaultStyle">    <item name="attr_one">attr one from default theme</item></style>
public MyTextView(Context context, AttributeSet attrs) {    super(context, attrs);    TypedArray typedArray = context.obtainStyledAttributes(attrs,            R.styleable.MyTextViewStyle,R.attr.MyTextViewStyleRef,R.style.MyTextViewDefaultStyle);    String strValue_one = typedArray.getString(R.styleable.MyTextViewStyle_attr_one);}

虽然获取的是attr_one,并且defStyleRes中给attr_one赋值了,但是得到的值还是null


最后,还可以在theme中直接赋值

<!-- Base application theme. --><style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">    <!-- Customize your theme here. -->    <item name="colorPrimary">@color/colorPrimary</item>    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>    <item name="colorAccent">@color/colorAccent</item>    <item name="attr_one">@string/app_name</item></style>
这种设置的优先级最低,而且如果是字符串,要把设置的值放到string资源里,否则会乱码


5.为什么要在这么多地方都可以设置:

在布局文件中对单个自定义控件属性赋值,这样需要每个控件都写一次

使用style赋值,可以在每个控件中写一句style=xxx就可以了

使用defStyleRes,defStyleAttr,theme赋值,直接写在theme文件中,设置activity或application的theme就可以对里面所有自定义控件属性赋值,相当于设置默认值




0 0
原创粉丝点击