自定義View之構造函數學習

在學習了博客裏前輩們的關於自定義View知識,來總結一下我學習自定義View構造函數的收穫,以及還有遇到的一些問題。遇到的問題,在以後解決後,會補充。

開始做一件事情,不要求自己一步做到完美,我會慢慢改進學習,去完善。

問題,驅動學習!


一、自定義View構造函數。

一共有四個構造函數,關於有四個參數的構造函數,是在Android API 21 之後才添加的。(AndroidL的新特性)

public class CustonViewComstructorStudy extends View {
    /**在Java代碼中,new一個View時候,通常使用*/
    public CustonViewComstructorStudy(Context context) {
        super(context);
    }

    /**在xml中引入一個視圖View時,這個View是我們自己定義在xml佈局文件當中。
     * 官方文檔:Constructor that is called when inflating a view from XML.*/
    public CustonViewComstructorStudy(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**在打印日誌裏,始終沒有看到程序走第三個構造函數*/
    public CustonViewComstructorStudy(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**基於Android API 21之後*/
    public CustonViewComstructorStudy(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
}


通過Android source可以看到,第二個,第三個構造函數都是調用了四個參數的構造函數,參數默認補0;


二、添加自定義屬性,給要操作的自定義View使用。(這些自定義屬性都是針對兩個,或者兩個以上參數的構造函數使用。)

1、在res目錄下,values文件內,新建一個attrs.xml。

通過<declare-styleable>標籤內的子標籤<attr>,添加View的自定義屬性。

<attr name="填寫屬性名稱" format="屬性類型">

代碼a attr.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--這裏是我們自己寫的內容,declare-styleable 的name默認提示與自定義View的類名一致-->
    <declare-styleable name="CustomViewStudy">
        <attr name="attr_string1" format="string"/>
        <attr name="attr_integer2" format="integer"/>
        <attr name="attr_boolean3" format="boolean"/>
        <attr name="attr_float4" format="float"/>
        <attr name="attr_color5" format="color"/>
        <attr name="attr_string6" format="string"/>
        <attr name="android:text"/>
        <attr name="android:textSize"/>

    </declare-styleable>


    <attr name="customize_reference" format="reference"/>
</resources>
解釋說明:
關於format的屬性類型,參看博客:http://blog.csdn.net/mybeta/article/details/39962235  自定義View屬性。

關於<atte name="customize_refernce" format="reference">也可以在<declare-styleable>標籤內,或者標籤外。移動位置以後,需要clean下代碼。任意一條屬性都可以。

2、隨即,一個問題來,<declare-styleable>標籤的作用是什麼?

首先不管是否使用<declare-styleable>,系統都會在R.attr中生成他們對應的attribute值。

public static final int customize_reference=0x7f010000;
如果使用了該標籤,系統還會在R.styleable中生成相關屬性。此處打一個Tag,後序還會用到該屬性。

以下代碼都在R.java中的 public static fianl class styleable{} 內部類中。

public static final int[] CustomViewStudy = {
            0x01010095, 0x0101014f, 0x7f0100a1, 0x7f0100a2,
            0x7f0100a3, 0x7f0100a4, 0x7f0100a5, 0x7f0100a6
        };
public static final int CustomViewStudy_android_text = 1;
public static final int CustomViewStudy_android_textSize = 0;
public static final int CustomViewStudy_attr_boolean3 = 4;
public static final int CustomViewStudy_attr_color5 = 6;
public static final int CustomViewStudy_attr_float4 = 5;
public static final int CustomViewStudy_attr_integer2 = 3;
public static final int CustomViewStudy_attr_string1 = 2;
public static final int CustomViewStudy_attr_string6 = 7;


三、聲明自定義屬性值(在添加attrs.xml中添加了屬性以後。)

1、首先要在根佈局中,添加命名空間:

//這是Android系統自帶
xmlns:android="http://schemas.android.com/apk/res/android

xmlns:cv="http://schemas.android.com/apk/res-auto"
      cv:是給自己的自定義屬性起的命名空間。放在Android系統自帶下邊即可。

      Tip: studio中是/apk/res-auto。eclispe中是全路徑名 /apk/自定義View全路徑名

2、在xml佈局中,創建自定義View佈局。不多講,上代碼:

代碼b:

<com.fight.liuhaoqing.a0917customviewconstructor2.CustomViewStudy
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        cv:attr_string1="@string/custom_view_string"
        style="@style/customize_style"/>

3、給自定義屬性賦值。

有三種方式賦值方式:

①直接在xml中,給屬性直接賦值。cv:attr_string1=@string/custom_view_string

②設置style,並在style中設置屬性值,style="@style/customsize_style" 

在values文件下styles.xml文件coding。見代碼c

③在Application與Activity中指定Theme,可以在Theme中指定在當前Activity或Application中

屬性默認值。也是在styles.xml文件coding。

通過attrs.xml 中聲明的reference屬性,在AppTheme中:

<item name="customize_reference">@style/customize_style_in_theme</item>調用。

問題是,我在打印時,該引用的自定義屬性值,沒有打印出來,懷疑是parent屬性導致。(留坑,待解決)

還有一種方式在Theme中,直接給自定義屬性賦值。在打印時,可以看到值。

代碼c :styles.xml

<resources>

    <!-- 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="customize_reference">@style/customize_style_in_theme</item>
        <item name="attr_string6">string6_in_app_theme</item>
    </style>
    <!--自定義View xml中引用的style 屬性賦值-->
    <style name="customize_style">
        <item name="attr_string1">你是我的眼</item>
        <item name="attr_integer2">9527</item>
        <item name="attr_boolean3">false</item>
    </style>

    <!--在AppTheme中引用的style 屬性賦值-->
    <style name="customize_style_in_theme">
        <item name="attr_integer2">8888</item>
        <item name="attr_float4">88.88</item>
        <item name="attr_color5">#000000</item>
    </style>

    <!--在defStyleAttribute不生效時的備用屬性賦值-->
    <style name="customize_style_def_attr_res">
        <item name="attr_color5">#ffffff</item>
    </style>

</resources>

四、兩個參數的構造函數。 主要看第二個參數:AttributeSet attrs

通過名字可以看出是一個Set集合。

源碼給出含義:@param attrs The attributes of the XML tag that is inflating the view.

public View(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

①關於attrs使用方式,上代碼:

public CustomViewStudy(Context context, AttributeSet attrs) {
        super(context, attrs);
        /**此處就是AttributeSet參數的本質上的使用方式。能夠取到當前View聲明的所有屬性。*/
        //獲取當前 attrs 集合Set大小。
        int count = attrs.getAttributeCount();
        for (int i = 0; i < count; i++) {
            String name = attrs.getAttributeName(i);//獲取當屬性名稱
            String value = attrs.getAttributeValue(i);//獲取當前屬性值

            Log.w(TAG, "Attribute name :" + name);
            Log.w(TAG, "Attribute value :" + value);
        }
        //通過如下結果可以看出,屬性有具體值時可以打印出值,如果是值引用,打印出來的就是一個引用值
        //所以,通過TypedArray ta = context.obtainStyledAttribute()方法來取當前View裏所有的屬性值。
//         W/CustomViewStudy: Attribute name :layout_width
//         W/CustomViewStudy: Attribute value :-2
//         W/CustomViewStudy: Attribute name :layout_height
//         W/CustomViewStudy: Attribute value :-2
//         W/CustomViewStudy: Attribute name :attr_string1
//         W/CustomViewStudy: Attribute value :@2131099681
    }


由於聲明賦值是通過引用,就暴露了其缺點,所以引入TypedArray類,Tag此處用到。因爲在<declare-styleable>,

在R.java中生成的是一個數組,見代碼b,如果佈局中的屬性的值是引用類型(比如:@string/custom_view_string),

如果使用AttributeSet去獲得最終的像素值,那麼需要第一步拿到id,第二步再去解析id。而TypedArray正是幫我們簡化了這個過程。


②獲取TypedArray 對象 需要通過  TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomViewStudy);方法。

但是obtainStyledAttributes方法最終調用的是getTheme去獲取該obtainStyledAttributes系列函數。

public TypedArray obtainStyledAttributes(int[]attrs)

//我主要使用這一個,給自定義屬性賦值,使用兩個參數的構造函數

public TypedArray obtainStyledAttributes(intresid,int[]attrs)throws NotFoundException {}

public TypedArray obtainStyledAttributes(AttributeSetset, int[]attrs,intdefStyleAttr,intdefStyleRes){} 

說一下其參數含義:

set:屬性值的集合

attrs:我們要獲取的屬性的資源ID的一個數組

defStyleAttr:這個是當前Theme中的一個attribute,是指向style的一個引用,當在layoutxml中和style中都沒有爲View指定屬性時

會從Theme中這個attribute指向的Style中查找相應的屬性值,這就是defStyle的意思,如果沒有指定屬性值,就用這個值,

所以是默認值,但這個attribute要在Theme中指定,且是指向一個Style的引用,如果這個參數傳入0表示不向Theme中搜索默認值

defStyleRes:這個也是指向一個Style的資源ID,但是僅在defStyleAttr爲0或defStyleAttr不爲0但Theme中沒有爲defStyleAttr屬性賦值時起作用

 public CustomViewStudy(Context context, AttributeSet attrs) {
        super(context, attrs);
        /**此處就是AttributeSet參數的本質上的使用方式。能夠取到當前View聲明的所有屬性。*/
        //獲取當前 attrs 集合Set大小。
//        int count = attrs.getAttributeCount();
//        for(int i = 0; i < count; i++){
//            String name = attrs.getAttributeName(i);//獲取當屬性名稱
//            String value = attrs.getAttributeValue(i);//獲取當前屬性值
//
//            Log.w(TAG,"Attribute name :" + name);
//            Log.w(TAG,"Attribute value :" + value);
//        }
           //通過如下結果可以看出,屬性有具體值時可以打印出值,如果是值引用,打印出來的就是一個引用值
           //所以,通過TypedArray ta = context.obtainStyledAttribute()方法來取當前View裏所有的屬性值。
//         W/CustomViewStudy: Attribute name :layout_width
//         W/CustomViewStudy: Attribute value :-2
//         W/CustomViewStudy: Attribute name :layout_height
//         W/CustomViewStudy: Attribute value :-2
//         W/CustomViewStudy: Attribute name :attr_string1
//         W/CustomViewStudy: Attribute value :@2131099681

        TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomViewStudy);
        String attr_str = ta.getString(R.styleable.CustomViewStudy_attr_string1);
        int attr_int = ta.getInteger(R.styleable.CustomViewStudy_attr_integer2,314);
        boolean attr_boolean = ta.getBoolean(R.styleable.CustomViewStudy_attr_boolean3,true);
        float attr_float = ta.getFloat(R.styleable.CustomViewStudy_attr_float4,3.14f);
        //getColor返回的是一個int值
        int attr_color = ta.getColor(R.styleable.CustomViewStudy_attr_color5, Color.parseColor("#5affefff"));//或者格式:Color.BLUE
        String attr_str6 = ta.getString(R.styleable.CustomViewStudy_attr_string6);

        Log.e(TAG,"perform 2 params constructor");
        Log.e(TAG,"Attribute attr_str:" + attr_str);
        Log.e(TAG,"Attribute attr_int:" + attr_int);
        Log.e(TAG,"Attribute attr_boolean:" + attr_boolean);
        Log.e(TAG,"Attribute attr_float:" + attr_float);
        Log.e(TAG,"Attribute attr_color:" + attr_color);
        Log.e(TAG,"Attribute attr_str6:" + attr_str6);

        ta.recycle();//調用後不會對下次使用造成影響。
    }

關於屬性值定義的優先級xml>style>Theme中的默認Sytle>默認Style(通過obtainStyledAttributes的第四個參數指定)>在Theme中直接指定屬性值

我在自己的打印日誌中,始終看不到通過Theme引用的style方式賦值屬性,以及默認的defStyleRes的賦值打印信息。順序就先牢記,(留坑,待補充)


關於三個參數構造,四個參數構造,我始終在代碼中,沒有執行走到,就先不寫了。自定義View基礎先學習到這。

2016-09-28修改start:

關於系統沒有調用三個參數,或者四個參數的構造方法,是需要我們自己去在代碼中,顯示調用三個參數,或者四個參數的構造方法。

2016-09-28修改end。


後記:雖然學習一邊,感覺總結有點亂,以後慢慢整理思路。

參考文章:

http://blog.csdn.net/lmj623565791/article/details/45022631/

http://www.cnblogs.com/angeldevil/p/3479431.html

http://blog.csdn.net/mybeta/article/details/39962235


	












發佈了30 篇原創文章 · 獲贊 3 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章