Android中自定義樣式與View的構(gòu)造函數(shù)中的第三個(gè)參數(shù)defStyle的意義

各木仔IP屬地: 上海
字?jǐn)?shù) 3,441

Android中自定義樣式與View的構(gòu)造函數(shù)中的第三個(gè)參數(shù)defStyle的意義

零、序

一、自定義Style

二、在XML中為屬性聲明屬性值

1. 在layout中定義屬性

2. 設(shè)置Style

3. 通過(guò)Theme指定

三、在運(yùn)行時(shí)獲取屬性值

1.?View的第三個(gè)構(gòu)造函數(shù)的第三個(gè)參數(shù)defStyle

2. obtailStyledAttributes

3. Example

四、結(jié)論與代碼下載

零、序

系統(tǒng)自帶的View可以在xml中配置屬性,對(duì)于寫(xiě)的好的Custom View同樣可以在xml中配置屬性,為了使自定義的View的屬性可以在xml中配置,需要以下4個(gè)步驟:

通過(guò)為自定義View添加屬性

在xml中為相應(yīng)的屬性聲明屬性值

在運(yùn)行時(shí)(一般為構(gòu)造函數(shù))獲取屬性值

將獲取到的屬性值應(yīng)用到View

怎么將獲取到的屬性值應(yīng)用到View就不用說(shuō)了,自己定義的屬性什么用處自己肯定是清楚的,所以接下來(lái)看一下前三點(diǎn)。

一、自定義Style

通過(guò)元素聲明Custom View需要的屬性即可,下面是一個(gè)例子,文件是res/values/attrs.xml

在上述xml中,我們聲明了Customize與CustomizeSyle,Customize包含了attr_one、attr_two、attr_three與attr_four四個(gè)attribute,CustomizeStyle也是一個(gè)attribute,但是卻沒(méi)有聲明在declare-styleable中。

定義在declare-styleable中與直接用attr定義沒(méi)有實(shí)質(zhì)的不同,上述xml中,無(wú)論attr_one - attr_four是否聲明在declare-styleable中,系統(tǒng)都會(huì)為我們?cè)赗.attr中生成5個(gè)attribute

publicstaticfinalclassattr {publicstaticfinalintCustomizeStyle=0x7f010004;publicstaticfinalintattr_one=0x7f010000;publicstaticfinalintattr_two=0x7f010001;publicstaticfinalintattr_three=0x7f010002;publicstaticfinalintattr_four=0x7f010003;

}

不同的是,如果聲明在declare-styleable中,系統(tǒng)還會(huì)為我們?cè)赗.styleable中生成相關(guān)的屬性。

publicstaticfinalclassstyleable {publicstaticfinalint[] Customize ={0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003};publicstaticfinalintCustomize_attr_one = 0;publicstaticfinalintCustomize_attr_two = 1;publicstaticfinalintCustomize_attr_three = 2;publicstaticfinalintCustomize_attr_four = 3;

}

如上所示,R.styleable.Customize是一個(gè)int[],而里面的元素的值正好和R.attr.attr_one - R.attr.attr_four一一對(duì)應(yīng),而R.styleable.Customize_attr_one等4個(gè)值就是R.attr.attr_one-R.attr.attr_four在R.styleable.Customize數(shù)組中的索引。這個(gè)數(shù)組和索引在第三步運(yùn)行時(shí)獲得屬性值時(shí)會(huì)用到,將attr分組聲明在declare-styleabe中的作用就是系統(tǒng)會(huì)自動(dòng)為我們生成這些東西,如果不聲明在declare-styleable中,我們完全可以在需要的時(shí)候自己構(gòu)建這個(gè)數(shù)組,由于數(shù)組是自己構(gòu)建的,每個(gè)屬性的下標(biāo)索引也就很清楚了,只是比較麻煩。以上一家之言,不過(guò)從使用及實(shí)驗(yàn)難上看確實(shí)是這樣的。

二、在xml中為相應(yīng)的屬性聲明屬性值

我們知道,在xml中為屬性賦值有幾種不同的方式

直接在layout中使用屬性

設(shè)置style并在style中設(shè)置屬性

Application和Activity可以指定theme,可以在theme中指定在當(dāng)前Application或Activity中屬性的默認(rèn)值

下面就分別看一下這三種方式

1. 直接在layout中使用屬性

在xml layout中使用自定義屬性和使用系統(tǒng)屬性差不多,不過(guò)屬性所屬的namespace不同,比如像下面這樣。

像layout_width等屬性屬于android的namespace,自定義的屬性屬于當(dāng)前程序的namespace,只需像聲明android的namespace一樣聲明當(dāng)前程序的namespace就好,只需要把上面紅色部分的android換成當(dāng)前程序的包名。應(yīng)用屬性的時(shí)候也需要注意屬性的namespace。

2. 設(shè)置style并在style中設(shè)置屬性

看上面xml中綠色的那一行,我們?yōu)镃ustomTextView聲明了一個(gè)style:ThroughStyle,這個(gè)Style很簡(jiǎn)單,只是指定了兩個(gè)屬性的值

attr one from styleattr two from style

注意,在style中我們聲明了attr_one的值,同時(shí)在xml中也直接向attr_one賦了值,最終用哪一個(gè)有個(gè)優(yōu)先級(jí)的問(wèn)題,后面在第三節(jié):在運(yùn)行時(shí)獲取屬性值中再說(shuō),接下來(lái)看下第三種方式。

3.?theme中指定在當(dāng)前Application或Activity中屬性的默認(rèn)值

attr one from themeattr two from themeattr three from theme@style/CustomizeStyleInThemeattr one from theme referenceattr two from theme referenceattr three from theme reference

在上述xml中,我們?cè)贏ppTheme中為attr_one、attr_two與attr_three指定了值,但是同時(shí)也為CustomizeStyle指定了一個(gè)reference,而在這個(gè)reference中為attr_one、attr_two與attr_three指定了值,CustomizeStyle就是我們?cè)赼ttrs.xml中定義的一個(gè)屬性。在theme中為屬性設(shè)置值的方式有兩這種,直接在theme中定義或通過(guò)另一個(gè)attribute引用一個(gè)style,這兩種方式還是有區(qū)別的,在下面的獲取屬性值一節(jié)中可以看到。

三、在運(yùn)行時(shí)獲取屬性值

在styles.xml中,我們同時(shí)定義一個(gè)DefaultCustomizeStyle的style,它的作用等下可以看到。

attr one from defalut style resattr two from defalut style resattr three from defalut style res

先看下CustomTextView的代碼

publicclassCustomTextViewextendsTextView {privatestaticfinalString TAG = CustomTextView.class.getSimpleName();publicCustomTextView(Context context) {super(context);

}publicCustomTextView(Context context, AttributeSet attrs) {this(context, attrs,R.attr.CustomizeStyle);? ? }publicCustomTextView(Context context, AttributeSet attrs,intdefStyle) {super(context, attrs, defStyle);

TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.Customize,defStyle,R.style.DefaultCustomizeStyle);? ? ? ? String one=a.getString(R.styleable.Customize_attr_one);

String two=a.getString(R.styleable.Customize_attr_two);

String three=a.getString(R.styleable.Customize_attr_three);

String four=a.getString(R.styleable.Customize_attr_four);

Log.i(TAG,"one:" +one);

Log.i(TAG,"two:" +two);

Log.i(TAG,"three:" +three);

Log.i(TAG,"four:" +four);

a.recycle();

}

}

主要代碼都在第三個(gè)函數(shù)中,這里也沒(méi)做什么,只是通過(guò)Context的obtainStyledAttributes獲得了前面定義的4個(gè)屬性的值并打印了出來(lái)。

View的第三個(gè)構(gòu)造函數(shù)的第三個(gè)參數(shù)defStyle

如果在Code中實(shí)例化一個(gè)View會(huì)調(diào)用第一個(gè)構(gòu)造函數(shù),如果在xml中定義會(huì)調(diào)用第二個(gè)構(gòu)造函數(shù),而第三個(gè)函數(shù)系統(tǒng)是不調(diào)用的,要由View(我們自定義的或系統(tǒng)預(yù)定義的View,如此處的CustomTextView和Button)顯式調(diào)用,比如在這里我們?cè)诘诙€(gè)構(gòu)造函數(shù)中調(diào)用了第三個(gè)構(gòu)造函數(shù),并將R.attr.CustomizeStyle傳給了第三個(gè)參數(shù)。

第三個(gè)參數(shù)的意義就如同它的名字所說(shuō)的,是默認(rèn)的Style,只是這里沒(méi)有說(shuō)清楚,這里的默認(rèn)的Style是指它在當(dāng)前Application或Activity所用的Theme中的默認(rèn)Style,以系統(tǒng)中的Button為例說(shuō)明。

publicButton(Context context) {this(context,null);

}publicButton(Context context, AttributeSet attrs) {this(context, attrs,com.android.internal.R.attr.buttonStyle);}publicButton(Context context, AttributeSet attrs,intdefStyle) {super(context, attrs, defStyle);

}

在Code中實(shí)例化View會(huì)調(diào)用第一個(gè)構(gòu)造函數(shù),在XML中定義會(huì)調(diào)用第二個(gè)構(gòu)造函數(shù),在Button的實(shí)現(xiàn)中都調(diào)用了第三個(gè)構(gòu)造函數(shù),并且defStyle的值是com.android.internal.R.attr.buttonStyle。buttonStyle是系統(tǒng)中定義的一個(gè)attribute,系統(tǒng)默認(rèn)有一個(gè)Theme,比如4.0中是Theme.Holo

...@android:style/Widget.DeviceDefault.Button....

上面是系統(tǒng)默認(rèn)的Theme,為buttonStyle指定了一個(gè)Style

@android:drawable/btn_default_holo_dark?android:attr/textAppearanceMedium@android:color/primary_text_holo_dark48dip64dip

這個(gè)Style定義了系統(tǒng)中Button的默認(rèn)屬性,如background等。

從文檔中第三個(gè)構(gòu)造函數(shù)的說(shuō)明中也可以看到,這個(gè)構(gòu)造函數(shù)的作用是View的子類(lèi)提供這個(gè)類(lèi)的基礎(chǔ)樣式

View(Contextcontext,AttributeSetattrs, int defStyleAttr)

Perform inflation from XML andapply a class-specific base style.

上面說(shuō)的都比較抽象,還是直接看實(shí)例代碼來(lái)的清楚明白,實(shí)驗(yàn)用的代碼上面全都貼完了,這里直接看結(jié)果,但在這之前要先看一個(gè)函數(shù):obtainStyledAtributes。

obtainStyledAtributes

我們要獲取的屬性值都是通過(guò)這個(gè)函數(shù)返回的TypedArray獲得的,這是官方說(shuō)明:obtainStyledAttributes,以下是函數(shù)原型:

publicTypedArray obtainStyledAttributes (AttributeSet set,int[] attrs,intdefStyleAttr,intdefStyleRes)

4個(gè)參數(shù)的意思分別是:

set:屬性值的集合

attrs:我們要獲取的屬性的資源ID的一個(gè)數(shù)組,如同ContextProvider中請(qǐng)求數(shù)據(jù)庫(kù)時(shí)的Projection數(shù)組,就是從一堆屬性中我們希望查詢(xún)什么屬性的值

defStyleAttr:這個(gè)是當(dāng)前Theme中的一個(gè)attribute,是指向style的一個(gè)引用,當(dāng)在layout xml中和style中都沒(méi)有為View指定屬性時(shí),會(huì)從Theme中這個(gè)attribute指向的Style中查找相應(yīng)的屬性值,這就是defStyle的意思,如果沒(méi)有指定屬性值,就用這個(gè)值,所以是默認(rèn)值,但這個(gè)attribute要在Theme中指定,且是指向一個(gè)Style的引用,如果這個(gè)參數(shù)傳入0表示不向Theme中搜索默認(rèn)值

defStyleRes:這個(gè)也是指向一個(gè)Style的資源ID,但是僅在defStyleAttr為0或defStyleAttr不為0但Theme中沒(méi)有為defStyleAttr屬性賦值時(shí)起作用

鏈接中對(duì)這個(gè)函數(shù)說(shuō)明勉強(qiáng)過(guò)得去,這里簡(jiǎn)要概括一下。對(duì)于一個(gè)屬性可以在多個(gè)地方指定它的值,如XML直接定義,style,Theme,而這些位置定義的值有一個(gè)優(yōu)先級(jí),按優(yōu)先級(jí)從高到低依次是:

直接在XML中定義>style定義>由defStyleAttr和defStyleRes指定的默認(rèn)值>直接在Theme中指定的值

看這個(gè)關(guān)系式就比較明白了,defStyleAttr和defStyleRes在前面的參數(shù)說(shuō)明中已經(jīng)說(shuō)了,“直接在Theme中指定的值”的意思在下面的示代碼中可以看到。

實(shí)驗(yàn)驗(yàn)證

相關(guān)的代碼都前面都已經(jīng)貼上了,不過(guò)為了方便查看,這里再把相關(guān)的XML一起貼一遍

main_activity.xmlattrs.xmlstyles.xmlattr one from themeattr two from themeattr three from theme@style/CustomizeStyleInThemeattr one from theme referenceattr two from theme referenceattr three from theme referenceattr one from styleattr two from styleattr one from defalut style resattr two from defalut style resattr three from defalut style res

在Code中是這樣獲取屬性的

publicCustomTextView(Context context, AttributeSet attrs) {this(context, attrs,R.attr.CustomizeStyle);}publicCustomTextView(Context context, AttributeSet attrs,intdefStyle) {super(context, attrs, defStyle);

TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.Customize,defStyle,R.style.DefaultCustomizeStyle);? ? ...}

CustomizeStyle是定義的一個(gè)attribute,DefaultCustomizeStyle是定義的一個(gè)style。

從代碼中可以看到,R.attr.CustomizeStyle就是前面提到的defStyleAttr,R.style.DefaultCustomizeStyle就是defStyleRes。

在Styles.xml中我們?yōu)锳pp定義了一個(gè)Theme:AppTheme,在這個(gè)Theme中直接為attr_one、attr_two、attr_three定義了屬性值,這個(gè)就是前面關(guān)系式中說(shuō)的直接在Theme中指定的值。

在AppTheme中同時(shí)定義了CustomizeStyle,引用了一個(gè)Style,在CustomTextView的構(gòu)造函數(shù)中分別打印了attr_one、attr_two、attr_three、attr_four的值,所以下面我們就可以通過(guò)Log輸出驗(yàn)證一下前面的關(guān)系式,如果一個(gè)attribute在多個(gè)位置都定義了值,究竟哪一個(gè)起作用。

如上圖所示:

attr_one同時(shí)在xml、style、defStyleAttr、defStyleRes與Theme中直接定義了值,但起作用的是在xml中的定義

attr_two同時(shí)在style、defStyleAttr、defStyleRes與Theme中直接定義了值,但起用的是在style中的定義

attr_three同時(shí)在defStyleAttr、defStyleRes與Theme中直接定義了值,但起作用的是defStyleAttr

attr_four在defStyleRes中定義了,但結(jié)果仍是0。

這可以說(shuō)明:

1. 直接在XML中定義>style定義>由defStyleAttr定義的值>defStyleRes指定的默認(rèn)值、直接在Theme中指定的值

2. defStyleAttr(即defStyle)不為0且在當(dāng)前Theme中可以找到這個(gè)attribute的定義時(shí),defStyleRes不起作用,所以attr_four雖然在defStyleRes(DefaultCustomizeStyle)中定義了,但取到的值仍為null。

為了看一下defStyleRes的作用,1. 我們?cè)贏ppTheme中加上attr_four的定義,2. 向obtainStyledAttributes的第三個(gè)參數(shù)傳入0,或者移除AppTheme中CustomizeStyle的定義,結(jié)果是一樣的

attr one from themeattr two from themeattr three from themeattr four from theme

由于defStyleAttr為0,或者defStyleAttr不為0但是我們沒(méi)有為這個(gè)屬性賦值,所以defStyleRes起作用,當(dāng)一個(gè)屬性沒(méi)有在XML和Style中賦值時(shí),系統(tǒng)會(huì)在defStyleRes(此處為DefaultCustomizeStyle)查找屬性的值。

我們看到attr_three的值來(lái)自defStyleRes,而attr_four的值來(lái)自Theme中的直接定義(DefaultCustomizeStyle定義了attr_one、atrr_two、attr_three)?,這就說(shuō)明

1. defStyleAtrtr即defStyle為0或Theme中沒(méi)有定義defStyle時(shí)defStyleRes才起作用

2. defStyleRes>在Theme中直接定義

結(jié)論

從前面的說(shuō)明可以得到以下結(jié)論:

要為自定義View自定義屬性,可以通過(guò)declare-styleable聲明需要的屬性

為了在Theme設(shè)置View的默認(rèn)樣式,可以同時(shí)定義一個(gè)format為reference的屬性att_a,在定義Theme時(shí)為這個(gè)attribute指定一個(gè)Style,并且在View的第二個(gè)構(gòu)造函數(shù)中將R.attr.attr_a作為第三個(gè)參數(shù)調(diào)用第三個(gè)構(gòu)造函數(shù)

可以定義一個(gè)Style作為T(mén)heme中沒(méi)有定義attr_a時(shí)View屬性的默認(rèn)值。

可以在Theme中直接為屬性賦值,但優(yōu)先級(jí)最低

當(dāng)defStyleAttr(即View的構(gòu)造函數(shù)的第三個(gè)參數(shù))不為0且在Theme中有為這個(gè)attr賦值時(shí),defStyleRes(通過(guò)obtainStyledAttributes的第四個(gè)參數(shù)指定)不起作用

屬性值定義的優(yōu)先級(jí):xml>style>Theme中的默認(rèn)Sytle>默認(rèn)Style(通過(guò)obtainStyledAttributes的第四個(gè)參數(shù)指定)>在Theme中直接指定屬性值

最后編輯于
©著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
3人點(diǎn)贊
總資產(chǎn)1共写了5761字获得5个赞共0个粉丝
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,786評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,986評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,204評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,964評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,354評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,554評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,106評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,918評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,093評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,342評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,755評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,009評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,839評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,107評(píng)論 2 375

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