Android中View自定義XML屬性詳解以及R.attr與R.styleable的區(qū)別

Android中View自定義XML屬性詳解以及R.attr與R.styleable的區(qū)別

Android中的各種Widget都提供了很多XML屬性,我們可以利用這些XML屬性在layout文件中為Widget的屬性賦值。

如下所示:

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

我們可以通過TextView所提供的XML屬性android:text為TextView的文本賦值滨攻。

我們在自定義View的時候也會經(jīng)常需要自定義View的XML屬性蛉鹿。

假設(shè)我們有一個自定義的View瓢阴,其類名是com.ispring.attr.MyView络拌,其中com.ispring.attr是應(yīng)用程序的包名鬼癣。

要想自定義XML屬性饵骨,總的來說包括三步:

  1. 在xml資源文件中定義各種attr翘悉,指定attr的數(shù)據(jù)類型。
  2. 在自定義View的構(gòu)造函數(shù)中解析這些從XML中定義的屬性值居触,將其存放到View對應(yīng)的成員變量中妖混。
  3. 在layout文件中為自定義View的XML屬性賦值。

首先轮洋,我們在res/values目錄下新建了一個名為attrs_my_views.xml文件制市,文件名是什么不重要,只要是xml文件就行砖瞧。我們在該文件中定義MyView所支持的XML屬性息堂。該文件的根結(jié)點是<resources>,我們在<resources>節(jié)點下可以添加多個<attr>節(jié)點块促,在<attr>節(jié)點中通過name指定XML屬性名稱荣堰,通過format指定XML屬性值的類型,如下圖所示:

這里寫圖片描述

由上圖我們可知竭翠,format支持的類型有enum振坚、boolean、color斋扰、dimension渡八、flag啃洋、float、fraction屎鳍、integer宏娄、reference、string逮壁。

當我們指定了XML屬性的名稱和屬性值的類型之后孵坚,我們就可以在layout文件中通過XML屬性為其賦值了。如下圖所示:

這里寫圖片描述

我們通過<com.ispring.attr.MyView>在layout中引入了MyView窥淆,為了能夠使用自定義屬性卖宠,我們通常要指定一個自定義的命名空間以區(qū)別于Android的命名空間xmlns:android,我們自定義命名空間的名字可以是任意的忧饭,通常我一般用xmlns:app扛伍。我的App的命名空間是com.ispring.attr,如果用Eclipse開發(fā)词裤,那么可以這樣定義命名空間xmlns:app=http://schemas.android.com/apk/res/com.ispring.attr认轨,但是在Android Studio中這樣定義命名空間會有問題誊抛。Android Studio使用Gradle進行build,而Gradle不允許自定義的命名空間以包名結(jié)尾,在Android Studio中可以這樣定義命名空間xmlns:app="http://schemas.android.com/apk/res-auto"困檩,這樣定義的命名空間自動指向當前App的命名空間归榕。

在正確定義app的命名空間之后走芋,我們就可以用app:customAttr為MyView的customAttr屬性賦值了陈症。如果我們將customAttr的format定義為boolean的,那么此處就只能填寫true或者false赖瞒,填寫其他類型的值會報錯女揭。

下面再對attr的format的類型進行一下說明。

  • boolean

    boolean表示attr是布爾類型的值栏饮,取值只能是true或false吧兔。

  • string

    string表示attr是字符串類型。

  • integer

    integer表示attr是整數(shù)類型袍嬉,取值只能是整數(shù)境蔼,不能是浮點數(shù)。

  • float

    float表示attr是浮點數(shù)類型伺通,取值只能是浮點數(shù)或整數(shù)箍土。

  • fraction

    fraction表示attr是百分數(shù)類型,取值只能以%結(jié)尾罐监,例如30%吴藻、120.5%等。

  • color

    color表示attr是顏色類型弓柱,例如#ff0000沟堡,也可以使用一個指向Color的資源侧但,比如@android:color/background_dark,但是不能用0xffff0000這樣的值航罗。

  • dimension

    dimension表示attr是尺寸類型禀横,例如取值16px、16dp伤哺,也可以使用一個指向<dimen>類型的資源燕侠,比如@android:dimen/app_icon_size者祖。

  • reference

    reference表示attr的值只能指向某一資源的ID立莉,例如取值@id/textView

  • enum

    enum表示attr是枚舉類型七问,在定義enum類型的attr時蜓耻,可以將attr的format設(shè)置為enum,也可以不用設(shè)置attr的format屬性械巡,但是必須在attr節(jié)點下面添加一個或多個enum節(jié)點刹淌。如下所示:

    <attr name="customAttr">
        <enum name="man" value="0" />
        <enum name="woman" value="1" />
    </attr>
    

    這樣attr的屬性值只能取man或woman了。

  • flag

    flag表示attr是bit位標記讥耗,flag與enum有相似之處有勾,定義了flag的attr,在設(shè)置值時古程,可以通過|設(shè)置多個值蔼卡,而且每個值都對應(yīng)一個bit位,這樣通過按位或操作符|可以將多個值合成一個值挣磨,我們一般在用flag表示某個字段支持多個特性雇逞,需要注意的是,要想使用flag類型茁裙,不能在attr上設(shè)置format為flag塘砸,不要設(shè)置attr的format的屬性,直接在attr節(jié)點下面添加flag節(jié)點即可晤锥。如下所示:

    <attr name="customAttr">
        <flag name="none" value="0" />
        <flag name="bold" value="0x1" />
        <flag name="italic" value="0x2" />
        <flag name="underline" value="0x4" />
    </attr>
    

    <attr>節(jié)點下通過定義多個<flag>表示其支持的值掉蔬,value的值一般是0或者是2的N次方(N為大于等于0的整數(shù)),對于上面的例子我們在實際設(shè)置值是可以設(shè)置單獨的值矾瘾,如none女轿、bold、italic霜威、underline谈喳,也可以通過|設(shè)置多個值,例如app:customAttr="italic|underline"戈泼。

    MyView直接繼承自View婿禽,我想讓MyView可以顯示文本赏僧,即我傳遞文本給MyView,MyView能畫出來扭倾,就相當于非常簡單的TextView淀零。

因此,我的attrs_my_view.xml如下所示:

<resources>
    <attr name="customText" format="string" />
    <attr name="customColor" format="color" />
</resources>

我們定義了兩個XML屬性膛壹,customText是一個string類型驾中,表示MyView要顯示的文本,customColor是color類型模聋,表示文本的顏色肩民。

對項目進行編譯之后會生成R.java文件,R.java文件對應(yīng)著R類链方。如果是Android Studio項目持痰,那么R文件的目錄是app\build\generated\source\r\debug\com\ispring\attr\R.java,在該文件中有內(nèi)部類public static final class attr祟蚀,在R.attr中會發(fā)現(xiàn)有customTextcustomColor工窍,如下圖所示:

這里寫圖片描述

R.attr.customTextR.attr.customColor分別是屬性customTextcustomColor的資源ID。

在使用MyView時前酿,我們可以在layout文件中為MyView設(shè)置customText和customColor兩個XML屬性患雏。layout文件如下所示:

<?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:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ispring.attr.MainActivity">

    <com.ispring.attr.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:customText="Hello World!"
        app:customColor="#FF0000FF"
        />

</RelativeLayout>

運行效果如下所示:

這里寫圖片描述

可以看出在界面上顯示了藍色的“Hello World!”文本,說明MyView的自定義屬性起作用了罢维。

我們看一下MyView的具體實現(xiàn)淹仑,MyView的代碼如下所示:

package com.ispring.attr;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {
    //存儲要顯示的文本
    private String mCustomText;
    //存儲文本的顯示顏色
    private int mCustomColor = 0xFF000000;
    //畫筆
    private TextPaint mTextPaint;
    //字體大小
    private float fontSize = getResources().getDimension(R.dimen.fontSize);

    public MyView(Context context) {
        super(context);
        init(null, 0);
    }

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

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

    private void init(AttributeSet attrs, int defStyle) {
        //首先判斷attrs是否為null
        if(attrs != null){
            //獲取AttributeSet中所有的XML屬性的數(shù)量
            int count = attrs.getAttributeCount();
            //遍歷AttributeSet中的XML屬性
            for(int i = 0; i < count; i++){
                //獲取attr的資源ID
                int attrResId = attrs.getAttributeNameResource(i);
                switch (attrResId){
                    case R.attr.customText:
                        //customText屬性
                        mCustomText = attrs.getAttributeValue(i);
                        break;
                    case R.attr.customColor:
                        //customColor屬性
                        //如果讀取不到對應(yīng)的顏色值,那么就用黑色作為默認顏色
                        mCustomColor = attrs.getAttributeIntValue(i, 0xFF000000);
                        break;
                }
            }
        }

        //初始化畫筆
        mTextPaint = new TextPaint();
        mTextPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setTextSize(fontSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if(mCustomText != null && !mCustomText.equals("")){
            mTextPaint.setColor(mCustomColor);
            //將文本繪制顯示出來
            canvas.drawText(mCustomText, 0, fontSize, mTextPaint);
        }
    }
}

我們在MyView中定義了兩個成員變量mCustomText和mCustomColor言津。MyView的幾個構(gòu)造函數(shù)都會調(diào)用init方法攻人,我們重點看一下init方法。

  • 傳遞給init方法的是一個AttributeSet對象悬槽,可以把它看成一個索引數(shù)組怀吻,這個數(shù)組里面存儲著屬性的索引,通過索引可以得到XML屬性名和屬性值初婆。

  • 通過調(diào)用AttributeSet的getAttributeCount()方法可以獲得XML屬性的數(shù)量蓬坡,然后我們就可以在for循環(huán)中通過索引遍歷AttributeSet的屬性名和屬性值。AttributeSet中有很多getXXX方法磅叛,一般必須的參數(shù)都是索引號屑咳,說幾個常用的方法:

    • 通過AttributeSet的public abstract String getAttributeName (int index)方法可以得到對應(yīng)索引的XML屬性名。

    • 通過AttributeSet的public abstract int getAttributeNameResource (int index)方法可以得到對應(yīng)索引的XML屬性在R.attr中的資源ID弊琴,例如R.attr.customText兆龙、R.attr.customColor。

    • 如果index對應(yīng)的XML屬性的format是string敲董,那么通過AttributeSet的public abstract String getAttributeName (int index)方法紫皇,可以得到對應(yīng)索引的XML屬性的值慰安,該方法返回的是String。除此之外聪铺,AttributeSet還有g(shù)etAttributeIntValue化焕、getAttributeFloatValue、getAttributeListValue等方法铃剔,返回不同類型的屬性值撒桨。

  • 我們通過attrs.getAttributeNameResource(i)得到獲取attr的資源ID,然后對attrResId進行switch判斷:

    • 如果是R.attr.customText键兜,表示當前屬性是customText凤类,我們通過attrs.getAttributeValue(i)讀取customText屬性值,并將其賦值給成員變量mCustomText蝶押。

    • 如果是R.attr.customColor踱蠢,表示當前屬性是customColor,由于Android中用一個4字節(jié)的int型整數(shù)表示顏色棋电,所以我們通過attrs.getAttributeIntValue(i, 0xFF000000)讀取了customColor的顏色值,并將其賦值給成員變量mCustomColor苇侵。

  • 我們重寫了MyView的onDraw方法赶盔,通過執(zhí)行mTextPaint.setColor(mCustomColor)把畫筆設(shè)置成mCustomColor的顏色,通過執(zhí)行canvas.drawText(mCustomText, 0, fontSize, mTextPaint)將mCustomText繪制到界面上榆浓。這樣于未,MyView就使用了customText和customColor這兩個XML屬性。


我們上面定義的customText和customColor這兩個<attr>屬性都是直接在<resources>節(jié)點下定義的陡鹃,這樣定義<attr>屬性存在一個問題:不能想通過style或theme設(shè)置這兩個屬性的值烘浦。

要想能夠通過style或theme設(shè)置XML屬性的值,需要在<resources>節(jié)點下添加<declare-styleable>節(jié)點萍鲸,并在<declare-styleable>節(jié)點下定義<attr>闷叉,如下所示:

<resources>
    <declare-styleable name="MyView">
        <attr name="customText" format="string" />
        <attr name="customColor" format="color" />
    </declare-styleable>
</resources>

需要給<declare-styleable>設(shè)置name屬性,一般name設(shè)置為自定義View的名字脊阴,我們此處設(shè)置為MyView握侧。

<declare-styleable>下面定義的<attr>屬性與直接在<resources>定義的<attr>屬性其實本質(zhì)上沒有太大區(qū)別,無論哪種方式定義<attr>嘿期,都會在R.attr類中定義R.attr.customText和R.attr.customColor品擎。不同的是,<declare-styleable name="MyView">節(jié)點會在R.styleable這個內(nèi)部類中有如下定義:

這里寫圖片描述

R.styleable.MyView是一個int數(shù)組备徐,其值為0x7f010038和 0x7f010039萄传。0x7f010038就是屬性R.attr.customText,0x7f010039就是屬性R.attr.customColor蜜猾。也就是R.styleable.MyView等價于數(shù)組[R.attr.customText, R.attr.customColor]秀菱。R.styleable.MyView的作用會在下面介紹西设。

我們同樣可以在R.styleable中發(fā)現(xiàn)R.styleable.MyView_customColor和R.styleable.MyView_customText這兩個ID。<declare-styleable name="MyView">中的name加上里面的<attr>屬性的name就組成了R.styleable中的MyView_customColor和MyView_customText答朋,中間以下劃線連接贷揽。如下圖所示:

這里寫圖片描述

其中R.styleable.MyView_customColor對應(yīng)R.attr.customColor,R.styleable.MyView_customText對應(yīng)R.attr.customText梦碗。MyView_customColor和MyView_customText的作用在下面介紹禽绪。

<declare-styleable>中定義的<attr>在MyView中需要通過調(diào)用theme的obtainStyledAttributes方法來讀取解析屬性值。obtainStyledAttributes有三個重載方法洪规,簽名分別如下所示:

  • public TypedArray obtainStyledAttributes (int[] attrs)

  • public TypedArray obtainStyledAttributes (int resid, int[] attrs)

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

我們先看第三個最復(fù)雜的方法印屁,在MyView中使用方法如下所示:

private void init(AttributeSet attributeSet, int defStyle) {
        //首先判斷attributeSet是否為null
        if(attributeSet != null){
            //獲取當前MyView所在的Activity的theme
            Resources.Theme theme = getContext().getTheme();
            //通過theme的obtainStyledAttributes方法獲取TypedArray對象
            TypedArray typedArray = theme.obtainStyledAttributes(attributeSet, R.styleable.MyView, 0, 0);
            //獲取typedArray的長度
            int count = typedArray.getIndexCount();
            //通過for循環(huán)遍歷typedArray
            for(int i = 0; i < count; i++){
                //通過typedArray的getIndex方法獲取指向R.styleable中對應(yīng)的屬性ID
                int styledAttr = typedArray.getIndex(i);
                switch (styledAttr){
                    case R.styleable.MyView_customText:
                        //如果是R.styleable.MyView_customText,表示屬性是customText
                        //通過typedArray的getString方法獲取字符串值
                        mCustomText = typedArray.getString(i);
                        break;
                    case R.styleable.MyView_customColor:
                        //如果是R.styleable.MyView_customColor斩例,表示屬性是customColor
                        //通過typedArray的getColor方法獲取整數(shù)類型的顏色值
                        mCustomColor = typedArray.getColor(i, 0xFF000000);
                        break;
                }
            }
            //在使用完typedArray之后雄人,要調(diào)用recycle方法回收資源
            typedArray.recycle();
        }

        ...
    }

我們在res/valeus/styles.xml文件中定義了如下style:

<style name="RedStyle">
        <item name="customText">customText in RedStyle</item>
        <!-- 紅色 -->
        <item name="customColor">#FFFF0000</item>
    </style>

然后我們在layout文件中將MyView的style屬性設(shè)置為上面的style,如下所示:

<com.ispring.attr.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:customText="customText in AttributeSet"
        style="@style/RedStyle"
        />

運行效果如下所示:

這里寫圖片描述

我們雖然沒有直接設(shè)置MyView的customText和customColor兩個屬性念赶,但是通過設(shè)置style屬性之后础钠,在效果上RedStyle中所定義的屬性值應(yīng)用到了MyView上了。

下面我們就來解釋一下init方法:

  • 首先我們通過getContext().getTheme()獲取到了當前MyView所在的Activity的theme叉谜。

  • 然后調(diào)用方法theme.obtainStyledAttributes(attributeSet, R.styleable.MyView, 0, 0)旗吁,該方法返回一個TypedArray對象。TypedArray是一個數(shù)組停局,通過該數(shù)組可以獲取應(yīng)用了style和theme的XML屬性值很钓。上面這個方法有四個參數(shù),后面兩個參數(shù)都是0董栽,大家暫且忽略不計码倦,后面會介紹。第一個參數(shù)還是AttributeSet對象锭碳,第二個參數(shù)是一個int類型的數(shù)組袁稽,該數(shù)組表示想要獲取的屬性值的屬性的R.attr中的ID,此處我們傳入的是R.styleable.MyView工禾,在上面我們已經(jīng)提到其值等價于[R.attr.customText, R.attr.customColor]运提,表示我們此處想獲取customText和customColor這兩個屬性的值。

  • 如果在layout文件中直接為MyView設(shè)置了某些XML屬性闻葵,那么這些XML屬性及其屬性值就會出現(xiàn)在AttributeSet中民泵,那么Android就會直接使用AttributeSet中該XML屬性值作為theme.obtainStyledAttributes()的返回值,比如在上面的例子中槽畔,我們通過app:customText="customText in AttributeSet"設(shè)置了MyView的XML屬性栈妆,最終運行的效果顯示的也是文本”customText in AttributeSet”。

  • 如果在layout文件中沒有為MyView設(shè)置某個XML屬性,但是給MyView設(shè)置了style屬性鳞尔,例如style="@style/RedStyle"嬉橙,并且在style中指定了相應(yīng)的XML屬性,那么Android就會用style屬性所對應(yīng)的style資源中的XML屬性值作為theme.obtainStyledAttributes()的返回值寥假。比如在上面的例子中市框,我們在layout文件中沒有設(shè)置app:customColor的值,但是在其style屬性所對應(yīng)的RedStyle資源中將customColor設(shè)置成了紅色#FFFF0000糕韧,最終文本也是以紅色顯示在界面上的枫振。

通過以上描述,我們可以知道萤彩,View的style屬性對應(yīng)的style資源中定義的XML屬性值其實是View直接在layou文件中定義XML屬性值的替補值粪滤,是用于補漏的,AttributeSet(即在layout中直接定義XML屬性)的優(yōu)先級高于style屬性中資源所定義的屬性值雀扶。


我們再看一下方法obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)中的第三個參數(shù)defStyleAttr杖小,這個參數(shù)表示的是一個<style>中某個屬性的ID,當Android在AttributeSet和style屬性所定義的style資源中都沒有找到XML屬性值時愚墓,就會嘗試查找當前theme(theme其實就是一個<style>資源)中屬性為defStyleAttr的值予权,如果其值是一個style資源,那么Android就會去該資源中再去查找XML屬性值转绷∥凹可能聽起來比較費勁,我們舉個例子议经。

我們更改了values/styles.xml文件,如下所示:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="myViewStyle">@style/GreenStyle</item>
    </style>

    <style name="GreenStyle">
        <item name="customText">customText in GreenStyle</item>
        <item name="customColor">#FF00FF00</item>
    </style>

    <style name="HelloWorldStyle">
        <item name="customText">Hello World!</item>
    </style>

    <style name="RedStyle">
        <item name="customText">customText in RedStyle</item>
        <item name="customColor">#FFFF0000</item>
    </style>

</resources>

我們添加了HelloWorldStyle和GreenStyle谴返,其中HelloWorldStyle只定義了customText的屬性值煞肾,而GreenStyle同時定義了customText和customColor的值,其中customColor定義為綠色嗓袱。

在AppTheme中籍救,我們設(shè)置了myViewStyle這個屬性的值,如下所示:

<item name="myViewStyle">@style/GreenStyle</item>

myViewStyle這個屬性是在values/attrs_my_view.xml中定義的渠抹,如下所示:

<resources>
    <attr name="myViewStyle" format="reference" />
    <declare-styleable name="MyView">
        <attr name="customText" format="string" />
        <attr name="customColor" format="color" />
    </declare-styleable>
</resources>

myViewStyle被定義為一個reference格式蝙昙,即其值指向一個資源類型,我們在AppTheme中將其賦值為@style/GreenStyle梧却,即在AppTheme中奇颠,myViewStyle的就是GreenStyle,其指向了一個style資源放航。

我們更改MyView代碼烈拒,如下所示:

//通過theme的obtainStyledAttributes方法獲取TypedArray對象
            TypedArray typedArray = theme.obtainStyledAttributes(attributeSet, R.styleable.MyView, R.attr.myViewStyle, 0);

注意,上面obtainStyledAttributes方法最后一個參數(shù)還是為0,可以忽略荆几,但是第三個參數(shù)的值不再是0吓妆,而是R.attr.myViewStyle。

然后我們更新layout文件吨铸,如下所示:

<com.ispring.attr.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        style="@style/HelloWorldStyle"
        />

我們?yōu)镸yView設(shè)置了style屬性行拢,其值為HelloWorldStyle。

程序運行效果如下所示:

這里寫圖片描述

我們發(fā)現(xiàn)結(jié)果是綠色的“Hello World!”诞吱,我們解釋一下原因舟奠。

  • 由于這次我們沒有通過layout文件直接設(shè)置MyView的XML屬性的值,所以AttributeSet本身是沒有XML屬性值的狐胎,我們直接忽略掉AttributeSet鸭栖。

  • 我們通過style="@style/HelloWorldStyle"為MyView設(shè)置了style為HelloWorldStyle,HelloWorldStyle中定義customText的屬性值為”Hello World!”握巢,所以最終customText的值就是”Hello World!”晕鹊,在界面上顯示的也是該值。

  • HelloWorldStyle中并沒有定義customColor屬性值暴浦。我們將theme.obtainStyledAttributes()方法的第三個參數(shù)設(shè)置為R.attr.myViewStyle溅话,此處的theme就是我們上面提到的AppTheme,Android會去AppTheme中查找屬性為myViewStyle的值歌焦,我們之前提到了飞几,它的值就是@style/GreenStyle,即GreenStyle独撇,由于該值是個style資源屑墨,Android就會去該資源中查找customColor的值,GreenStyle定義了customColor的顏色為綠色纷铣,所以MyView最終所使用的customColor的值就是綠色卵史。

綜上,我們發(fā)現(xiàn)搜立,此處的第三個參數(shù)的作用是:當在AttributeSet和style屬性中都沒有找到屬性值時以躯,就去Theme的某個屬性(即第三個參數(shù))中查看其值是否是style資源,如果是style資源再去這個style資源中查找XML屬性值作為替補值啄踊。


<a name="t3" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: normal; outline: none;"></a>obtainStyledAttributes方法之defStyleRes

最后我們看一下方法obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)中的第四個參數(shù)defStyleRes忧设。與defStyleAttr類似,defStyleRes是前面幾項的替補值颠通,defStyleRes的優(yōu)先級最低址晕。與defStyleAttr不同的是,defStyleRes本身直接表示一個style資源蒜哀,而theme要通過屬性defStyleAttr間接找到style資源斩箫。

我們添加了BlueStyle這個style吏砂,如下所示:

<style name="BlueStyle">
    <item name="customText">customText in BlueStyle</item>
    <item name="customColor">#FF0000FF</item>
</style>

并將layout文件改為如下所示:

<com.ispring.attr.MyView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

我們更改MyView代碼如下所示:

TypedArray typedArray = theme.obtainStyledAttributes(attributeSet, R.styleable.MyView, 0, R.style.BlueStyle);

第三個參數(shù)設(shè)置為0,第四個參數(shù)不再是0乘客,而是R.style.BlueStyle狐血。運行界面如下所示:

這里寫圖片描述

只有第三個參數(shù)defStyleAttr為0或者該屬性在theme中找不到時,才會使用第四個參數(shù)defStyleRes易核。如果第三個參數(shù)defStyleAttr不為0匈织,但是theme的defStyleAttr所對應(yīng)的屬性值中的style沒有定義任何XML屬性值,那么第四個參數(shù)也不會defStyleRes被使用牡直。


<a name="t4" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: normal; outline: none;"></a>總結(jié)

  • 可以不通過<declare-styleable>節(jié)點定義XML屬性缀匕,不過還是建議將XML屬性定義在<declare-styleable>節(jié)點下,因為這樣Android會在R.styleable下面幫我們生成很多有用的常量供我們直接使用碰逸。

  • obtainStyledAttributes方法中乡小,優(yōu)先級從高到低依次是:直接在layout中設(shè)置View的XML屬性值(AttributeSet) > 設(shè)置View的style屬性 > defStyleAttr > defStyleRes

http://blog.csdn.net/iispring/article/details/50708044

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饵史,隨后出現(xiàn)的幾起案子满钟,更是在濱河造成了極大的恐慌,老刑警劉巖胳喷,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件湃番,死亡現(xiàn)場離奇詭異,居然都是意外死亡吭露,警方通過查閱死者的電腦和手機吠撮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讲竿,“玉大人泥兰,你說我怎么就攤上這事√赓鳎” “怎么了逾条?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長投剥。 經(jīng)常有香客問我,道長担孔,這世上最難降的妖魔是什么江锨? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮糕篇,結(jié)果婚禮上啄育,老公的妹妹穿的比我還像新娘。我一直安慰自己拌消,他們只是感情好挑豌,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般氓英。 火紅的嫁衣襯著肌膚如雪侯勉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天铝阐,我揣著相機與錄音址貌,去河邊找鬼。 笑死徘键,一個胖子當著我的面吹牛练对,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播吹害,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼螟凭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了它呀?” 一聲冷哼從身側(cè)響起螺男,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钟些,沒想到半個月后烟号,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡政恍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年汪拥,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片篙耗。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡迫筑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宗弯,到底是詐尸還是另有隱情脯燃,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布蒙保,位于F島的核電站辕棚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏邓厕。R本人自食惡果不足惜逝嚎,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望详恼。 院中可真熱鬧补君,春花似錦、人聲如沸昧互。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叽掘,卻和暖如春楣铁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背够掠。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工民褂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疯潭。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓赊堪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親竖哩。 傳聞我的和親對象是個殘疾皇子哭廉,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容