自定義View(二)自定義View的構造方法及自定義屬性

       更多內容:

       (一)自定義View的分類點擊打開鏈接
       (二)自定義View的構造方法及自定義屬性
       (三)自定義View的常用方法(測量、繪製、位置)
       (四)自定義View的具體實現
       (五)事件分發機制

      

         一、自定義View的構造方法

         無論是繼承自View還是ViewGroup的自定義控件,編譯器都會提示我們

         Implicit super constructor ViewGroup() is undefined for default constructor. Must define an explicit constructor          

        意思是基類沒有無參的構造方法,必須定義一個帶參的構造方法。

        我們可以重載下面三個構造方法(API21已經有四個參數的構造方法)。

   public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        
    }

      首先解決兩個問題

      一、我們在構造方法中具體做什麼

      一般做一些初始化工作,獲取自定義屬性、獲取子View等等,以後的demo中會具體講解


     二、如何選擇構造方法

     關於三個方法的選擇,源碼的註釋裏已經寫得非常清楚了

    /**
     * Simple constructor to use when creating a view from code.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     */
    public View(Context context) {
                      ……
    }
       帶一個參數的構造方法:

       Simple constructor to use when creating a view from code

       當我們在代碼裏創建一個view時,使用此方法

    /**
     * Constructor that is called when inflating a view from XML. This is called
     * when a view is being constructed from an XML file, supplying attributes
     * that were specified in the XML file. This version uses a default style of
     * 0, so the only attribute values applied are those in the Context's Theme
     * and the given AttributeSet.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @see #View(Context, AttributeSet, int)
     */
    public View(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

         帶兩個參數的構造方法:

        Constructor that is called when inflating a view from XML. This is called when a view is being constructed from an XML file, supplying attributes   that were specified in the XML file. This version uses a default style of  0, so the only attribute values applied are those in the Context's Theme and the given AttributeSet.

        當我們在xml文件中創建一個控件時,使用此方法。這個方法傳遞了控件在xml文件中定義的所有屬性(包括自定義屬性),即attars。它所使用的的默認樣式是0,這意味Context和Theme給定的attributeset是唯一用到的屬性值。

    /**
     *  Perform inflation from XML and apply a class-specific base style. This
     * constructor of View allows subclasses to use their own base style when
     * they are inflating. For example, a Button class's constructor would call
     * this version of the super class constructor and supply
     * <code>R.attr.buttonStyle</code> for <var>defStyle</var>; this allows
     * the theme's button style to modify all of the base view attributes (in
     * particular its background) as well as the Button class's attributes.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @param defStyleAttr An attribute in the current theme that contains a
     *        reference to a style resource to apply to this view. If 0, no
     *        default style will be applied.
     * @see #View(Context, AttributeSet)
     */
    public View(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context);

      ……
        }

         帶三個參數的構造方法:

         Perform inflation from XML and apply a class-specific base style. This constructor of View allows subclasses to use their own base style when
they are inflating. For example, a Button class's constructor would call this version of the super class constructor and supply
R.attr.buttonStyle for defStyle ; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes. 

        在xml創建一個控件並且使用某個特定類型的基礎樣式時,使用此方法。

        這個方法允許子類在加載時使用它們自己的基礎樣式。比如說,一個按鈕類重載此構造方法時,將要調用基類的同類型構造方法,使用R.attr.buttonStyle作爲默認樣式。這使得theme的按鈕樣式修改所有基礎控件屬性(特別是其背景)以及按鈕類的屬性。

       這裏我們再看一下defStyleAttr參數的解釋:

       defStyleAttr: An attribute in the current theme that contains a reference to a style resource to apply to this view. If 0, no default style will be applied.

        當前theme中引用自style的屬性,如果是0的話,不使用任何style。

        補充一句:系統不會主動的調用這個方法,需要我們顯式的調用,比如:

  public MyView(Context context, AttributeSet attrs) {
        //顯式調用三個參數的構造方法 ,將R.attr.buttonStyle作爲控件的基礎樣式
        this(context, attrs, R.attr.buttonStyle);
    }
    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }
        當我們顯式的調用這個方法時,我們的自定義控件將使用這個defStyle作爲基礎的樣式,但是這個defStyle所定義的屬性是可以被覆蓋的。比如我們在自定義控件時在xml文件中重寫了defStyle的某些屬性,這些屬性就被覆蓋了。

       這是因爲同時定義一個屬性時,是有優先級的:xml>style>defStyle>theme


       在實際運用中,爲了方便,我們一般會按如下方式同時重載這三個構造方法

   public MyView(Context context) {
		this(context, null);// 調用兩個參數的構造方法

	}
	
    public MyView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);//調用三個參數的構造方法

    }
    
    public MyView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);//調用基類構造方法

    }


       二、自定義View的自定義屬性

         對於一個自定義控件,它擁有基類所有的屬性,同時也可以定義自己的屬性,這就是自定義屬性

       舉個最簡單的例子,我們現在自義定一個圓形頭像,首先讓它繼承ImageView,這樣就擁有了背景這個屬性。但是作爲一個圓形頭像它是需要半徑這個屬性的,這就需要我們去自定義了。


       ①在res文件的values目錄下,創建一個xml文件,我們將在這個文件中編寫自義定屬性。我創建的是attrs.xml ,名字不是固定的可以自己取。

         

         ② <declare-styleable name="控件名">       
                <attr name="屬性名" format="屬性類型" /> 

                  ……   
           </declare-styleable>
    

<resources>
    
     <declare-styleable name="CircleIcon">       
        <attr name="circle_radius" format="float" />     
     </declare-styleable> 
    
</resources>
          format選項說明及使用,這篇博客歸納的非常完整Android自定義屬性時format選項參數說明及用法

        ③我們怎麼得到已經寫好的自定義屬性呢,還記得剛剛講過的兩個參數的構造方法嗎,它的參數 AttributeSet attrs傳入了自定義控件的所有屬性,包括xml文件裏申明的,也包括自定義的,因此我們在兩個參數的構造方法中獲取自定義屬性

 public CircleView(Context context, AttributeSet attrs) {
        this(context, attrs, defStyle);//調用基類構造方法
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.CircleIcon);//  <declare-styleable name="CircleIcon"> 
        float radius = a.getFloat(R.styleable.CircleIcon_circle_radius,//控件名_屬性名
                1);
        a.recycle();//一定要寫
    }

       當我們獲取了自定義屬性時,就可以使用它們來構建控件了,具體的內容將在後面的文章詳細講解








    



                 



















      

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章