自定义View知识梳理

1.自定义View的构造函数调用时机

public class MyView extends View {
            public MyView(Context context) {  //在代码中实例化View时调用这个构造函数
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {    //在XML中定义会调用这个构造函数
        super(context, attrs);
        for (int i=0;i<attrs.getAttributeCount();i++){
            Log.d("MyView",attrs.getAttributeName(i));
        }
    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {        //第二个构造函数中可以显示调用这个构造函数
        super(context, attrs, defStyleAttr);
    }


}

2.自定义View属性

在Android中要增加自定义属性,需要依靠attrs.xml文件。这里指定的自定义属性,是在layout布局文件中使用的不是以android开头的属性。

res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView">
        <attr name="textColor" format="color"/>
        <attr name="textSize" format="dimension" />
        <attr name="textValue" format="string" />
    </declare-styleable>
</resources>

声明在declare-styleable中,系统还会为我们在R.styleable中生成相关的属性。

public static final class styleable {
        public static final int[] MyView = {
            0x7f0100b1, 0x7f0100b2, 0x7f0100b3
        };
/*下面为上面数组的索引*/
public static final int MyView_textColor = 0;
public static final int MyView_textSize = 1;
public static final int MyView_textValue = 2; 
}

在layout中声明名称空间就可以使用这些属性了(xmlns:ad=”http://schemas.android.com/apk/res-auto”)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.jimli.customviewtest.MyView
        xmlns:ad="http://schemas.android.com/apk/res-auto"
        android:id="@+id/MyView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ad:textSize="20sp"/>
</LinearLayout>

那么这些属性是如何应用到自定义的View中的呢?
当我们在xml中给自定义属性赋值时 (ad:textSize=”20sp”) 当实例化属性时,这些属性会传入attrs参数中,我们就可以取出这些属性,对自定义View进行操作。

3.构造函数参数作用

xml中定义的属性会作为参数传入attrs中,见代码试例如下

这是xml文件:

    <com.example.jimli.customviewtest.MyView
        android:id="@+id/MyView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ad:textSize="20sp"/>

然后我们观察attrs中的值

 public MyView(Context context, AttributeSet attrs) {    //在XML中定义会调用这个构造函数
        super(context, attrs);
        for (int i=0;i<attrs.getAttributeCount();i++){
            Log.d("MyView",attrs.getAttributeName(i));
        }
    }

输出如下:

com.example.jimli.customviewtest D/MyView: id
com.example.jimli.customviewtest D/MyView: layout_width
com.example.jimli.customviewtest D/MyView: layout_height
com.example.jimli.customviewtest D/MyView: textSize

正好对应xml中的四个属性。这样一来,我们对attrs这个参数也就明白了,当在xml定义属性时,就会作为参数传入attrs属性。

public MyView(Context context, AttributeSet attrs, int defStyleAttr)

第三个参数的意义就如同它的名字所说的,是默认的Style,只是这里没有说清楚,这里的默认的Style是指它在当前Application或Activity所用的Theme中的默认Style。
为什么需要这个参数呢?因为当我们设置主题时,将会应用到所有的View上,为了也要方便我们的自定义View来使用这个主题属性,这就是这个参数的意义(纯属个人理解)

4.obtainStyledAttributes

public TypedArray obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)

这个函数的四个参数我结合网上的一些文章来分析下我个人的理解

看网上的解释:

     set:属性值的集合(也就是从Xml中传过来的属性值集合 见上面的输出)

    attrs:我们要获取的属性的资源ID的一个数组,如同ContextProvider中请求数据库时的Projection数组,就是从一堆属性中我们希望查询什么属性的值

    defStyleAttr:这个是当前Theme中的一个attribute,是指向style的一个引用,当在layout xml中和style中都没有为View指定属性时,会从Theme中这个attribute指向的Style中查找相应的属性值,这就是defStyle的意思,如果没有指定属性值,就用这个值,所以是默认值,但这个attribute要在Theme中指定,且是指向一个Style的引用,如果这个参数传入0表示不向Theme中搜索默认值

    defStyleRes:这个也是指向一个Style的资源ID,但是仅在defStyleAttr为0或defStyleAttr不为0但Theme中没有为defStyleAttr属性赋值时起作用

  链接中对这个函数说明勉强过得去,这里简要概括一下。对于一个属性可以在多个地方指定它的值,如XML直接定义,style,Theme,而这些位置定义的值有一个优先级,按优先级从高到低依次是:

直接在XML中定义>style定义>由defStyleAttr和defStyleRes指定的默认值>直接在Theme中指定的值

  看这个关系式就比较明白了,defStyleAttr和defStyleRes在前面的参数说明中已经说了,“直接在Theme中指定的值”的意思在下面的示代码中可以看到。

下面来看看例子:

xml文件

    <com.example.jimli.customviewtest.MyView
        android:id="@+id/MyView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ad:textSize="20sp"/>
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array=context.obtainStyledAttributes(attrs,R.styleable.MyView);     //重点看这句
        Log.i("MyView", "one:" + array.getString(R.styleable.MyView_textColor));
        Log.i("MyView", "two:" + array.getString(R.styleable.MyView_textSize));
        Log.i("MyView", "three:" + array.getString(R.styleable.MyView_textValue));
        array.getString(R.styleable.MyView_textColor);
        array.getString(R.styleable.MyView_textSize);
        array.getString(R.styleable.MyView_textValue);
        array.recycle();
    }

重点看这句:

TypedArray array=context.obtainStyledAttributes(attrs,R.styleable.MyView); 

R.styleable.MyView指定了我们想要获得什么数组,R.styleable.MyView可以见上面,我为了方便贴一下:

public static final class styleable {
        public static final int[] MyView = {
            0x7f0100b1, 0x7f0100b2, 0x7f0100b3
        };  //想要获取的数组
/*下面为上面数组的索引*/
public static final int MyView_textColor = 0;
public static final int MyView_textSize = 1;
public static final int MyView_textValue = 2; 
}

在Xml文件中我们指定了ad:textSize的值,所以优先从xml取出textSize的值,如果我们把 attrs置空 ,像这样

TypedArray array=context.obtainStyledAttributes(null,R.styleable.MyView); 

这时候取出来的三个都为空。

这时候就要用到后面的俩个参数了:(int defStyleAttr, int defStyleRes)attrs没有值的时候就去默认主题找。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值