Android自定義控件的四個構造方法與自定義屬性defStyleAttr,defStyleRes詳解

當我們寫一個自定義控件時需要重寫其構造方法,比如這樣:

//1個參數的構造方法
    public BaseLoadingLayout(Context context) {
        super(context);
    }
//2個參數的構造方法
    public BaseLoadingLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
//3個參數的構造方法
    public BaseLoadingLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

//4個參數的構造方法
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public BaseLoadingLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr,defStyleRes);
    }

其中,第四個構造方法(也就是有四個參數的方法)是sdk21之后view和viewGroup才有的。
如果是new一個自定義view的話,會根據參數來進行構造方法的重載。

直接在xml里引用控件時,對LayoutInflater代碼分析,發現會調用兩個參數的構造方法,所以要想自定義view能在xml里被引用,要重寫其兩個參數的構造方法。

 if (mConstructorArgs[0] == null) {
                // Fill in the context if not already within inflation.
                mConstructorArgs[0] = mContext;
            }
            Object[] args = mConstructorArgs;
            args[1] = attrs;

            final View view = constructor.newInstance(args);

自定義view有時需要自定義屬性
1.在value/attrs.xml里新建StyleableRes 也就是declare-styleable 節點,如下:

 <declare-styleable name="CircleProgressbar">
        <attr name="radius" format="dimension"/>
        <attr name="strokeWidth" format="dimension"/>
        <attr name="ringColor" format="color"/>
        <attr name="textColor" format="color"/>
    </declare-styleable>

 <attr name="myProgressBaraaa" format="reference"/>

2.在view構造方法里取出屬性值,并根據屬性操作view,代碼如下:

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressbar, R.attr.DefaultBaseLoadingLayoutViewStyle , R.style.DefaultCustomViewStyle);
        radius = typeArray.getDimension(R.styleable.CircleProgressbar_radius, 80);
        strokeWidth = typeArray.getDimension(R.styleable.CircleProgressbar_strokeWidth, 10);
        ringColor = typeArray.getColor(R.styleable.CircleProgressbar_ringColor, 0xFF0000);
        textColor = typeArray.getColor(R.styleable.CircleProgressbar_textColor, 0xFFFFFF);
        typeArray.recycle();
    }

其中obtainStyledAttributes方法用來得到最終的view的所有屬性值,想寫好一個自定義view是要考慮如何獲取該view的屬性,給view添加屬性最直接的方式就是寫在layout的xml里面,如果xml里面沒寫屬性或者想直接new一個view時,我們就要去theme里面找,看有theme里面有沒有定義這個view的屬性,如果沒有,需要給view設置一個默認的屬性值,obtainStyledAttributes方法就是為了完成以上任務的,來看看他的參數有哪些:

   public final TypedArray obtainStyledAttributes(AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
        return getTheme().obtainStyledAttributes(
            set, attrs, defStyleAttr, defStyleRes);
    }
AttributeSet set 代表控件寫在布局xml里的屬性
@StyleableRes int[] attrs :我們想要得到的所有屬性,這是我們自己聲明的value/attrs.xml里declare-styleable 節點下的屬性
@AttrRes int defStyleAttr:下文再表
/@StyleRes int defStyleRes:如果defStyleAttr傳的是0,則取defStyleRes里面的style屬性

下面我們來講defStyleAttr
如果set 為null時(set 是從xml里取到的屬性值,當我們直接new一個view而不是從xml里inflate時,set為null),就從defStyleAttr里讀取屬性值,defStyleAttr從名字來看,它帶一個attr,說明它是view的一個屬性,只是這個屬性是用來定義這個view的默認樣式的(當set為空時的樣式)。那我們要如何使用它呢?很多人都簡單粗暴的直接傳0進去,傳0進去這一個參數將使view失去默認樣式,我們可以定義一個默認樣式:
第一步,在values/attrs.xml里加上一個自定義view樣式的屬性

 <attr name="costumeViewStyle" format="reference"/>

第二步,在values/attrs.xml里定義一個自定義view的默認樣式,比如:

   <style name="myProgressBarRefer" parent="Base.Widget.AppCompat.ProgressBar">
        <item name="android:indeterminateTint" tools:targetApi="lollipop">#fff787</item>
        <item name="android:indeterminateTintMode" tools:targetApi="lollipop">@color/colorYellow</item>
        <item name="android:minHeight">200dp</item>>
        <item name="android:minWidth">200dp</item>
    </style>

第三步,在values/styles.xml里定義一個theme,theme里加上一行對自定義屬性,并引用剛剛定義好的默認style

  <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="costumeViewStyle">@style/myProgressBarRefer</item>

  </style>

第四步,把我們自定義的theme應用在application或者對于的activity 。
說白了defStyleAttr就是一個view的style屬性,該屬性可以在theme里被賦值

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容