Android View 四個(gè)構(gòu)造函數(shù)詳解

本文是在網(wǎng)上看到,感覺(jué)很好,就厚著臉皮拿過(guò)來(lái)了,在這里先對(duì)原著大牛叩罪,有時(shí)候遇到一個(gè)問(wèn)題想在網(wǎng)上尋找答案,但能找到自己想要的答案既費(fèi)時(shí)又費(fèi)力,最終費(fèi)了九牛二虎之力找到,又怕過(guò)些時(shí)間鏈接失效了,姑且把原文拿來(lái)自己保存,以便日后查閱,還是要叩謝作者,望諒解。

在開(kāi)發(fā)android開(kāi)發(fā)過(guò)程中,很多人都會(huì)遇到自定義view,一般都需要繼承自View類(lèi),而當(dāng)你打開(kāi)View類(lèi)的源碼時(shí),發(fā)現(xiàn)會(huì)有四個(gè)構(gòu)造函數(shù),那么這四個(gè)構(gòu)造函數(shù)是如何使用的呢,怎么合理的利用四個(gè)構(gòu)造函數(shù)呢,本文將進(jìn)行一定探究,希望能夠拋磚引玉。

一View類(lèi)的四個(gè)構(gòu)造函數(shù)

先從android源碼中把四個(gè)構(gòu)造函數(shù)拉出來(lái)看看。。

1第一個(gè)構(gòu)造函數(shù)

1

2第二個(gè)構(gòu)造函數(shù)

2

3 第三個(gè)構(gòu)造函數(shù)

3

4 第4個(gè)構(gòu)造函數(shù)

4

二 構(gòu)造函數(shù)的調(diào)用

【第一個(gè)問(wèn)題】

如果我們?cè)诶^承了View類(lèi)實(shí)現(xiàn)自定義類(lèi)時(shí),需要重寫(xiě)哪個(gè)構(gòu)造函數(shù)?

回答這個(gè)問(wèn)題,首先需要知道,在定義了View時(shí),我們都調(diào)用了哪個(gè)構(gòu)造函數(shù)。我這里做了一個(gè)簡(jiǎn)單的實(shí)驗(yàn):

我們聲明一個(gè)簡(jiǎn)單的View,繼承自TextView,什么都不改,只是在4個(gè)constructor中打印幾個(gè)tag,查看到底哪個(gè)構(gòu)造函數(shù)被調(diào)用。

【實(shí)驗(yàn)】

實(shí)驗(yàn)

在布局文件layout中加上這個(gè)View

layout

[實(shí)驗(yàn)結(jié)果]

結(jié)果

【實(shí)驗(yàn)—結(jié)果分析】

通過(guò)上面的實(shí)驗(yàn)輸出中的Second Constructor,我們知道,當(dāng)我們自定義一個(gè)View,且在布局文件中引用時(shí),在系統(tǒng)初始化該View時(shí),調(diào)用的是第二個(gè)構(gòu)造函數(shù),而且我還把第二個(gè)構(gòu)造函數(shù)中的attrs參數(shù)也打了出來(lái),可以看出其中的參數(shù)attrs是我們?cè)趚ml中配置的參數(shù)。

其實(shí)第一個(gè)構(gòu)造函數(shù)用途并不大,主要是在Java代碼中聲明一個(gè)View時(shí)所用,不過(guò)如果只用第一個(gè)構(gòu)造函數(shù),聲明的View并沒(méi)有任何的參數(shù),基本是個(gè)空的View對(duì)象。

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

在回答了第一個(gè)問(wèn)題后,還有后兩個(gè)構(gòu)造函數(shù),這是本文的重點(diǎn)。

1 View的屬性和主題

在說(shuō)后兩個(gè)構(gòu)造函數(shù)之前,先說(shuō)說(shuō)View的屬性,在View中有不同的屬性,比如layout_width等,TextView還有textColor這些特有的屬性,我們可以對(duì)這些屬性進(jìn)行不同的配置進(jìn)而實(shí)現(xiàn)不同的效果。而且屬性也可以在不同的位置進(jìn)行配置。以TextView為例,android:textColor這個(gè)屬性可以在多個(gè)地方配置,可以直接寫(xiě)在xml中,可以在xml中以style的形式定義,這兩種是我們平時(shí)見(jiàn)得較多的,其實(shí)還有一種背后的力量可以給屬性賦值,那就是主題。

我們?cè)赼ndroid中可以配置一個(gè)主題,從而使得一些View即使你不對(duì)其進(jìn)行任何配置,它都會(huì)有一些已經(jīng)默認(rèn)賦值的屬性,這就是主題的功勞。

View類(lèi)的后兩個(gè)構(gòu)造函數(shù)都是與主題相關(guān)的,也就是說(shuō),在你自定義View時(shí),如果不需要你的View隨著主題變化而變化,有前兩個(gè)構(gòu)造函數(shù)就OK了,但是如果你想你的View隨著主題變化而變化,就需要利用后兩個(gè)構(gòu)造函數(shù)了。

2 屬性賦值的優(yōu)先級(jí)

當(dāng)可以在多個(gè)地方賦值屬性時(shí),一個(gè)問(wèn)題就不可避免的出現(xiàn)了:優(yōu)先級(jí)?。?!

一個(gè)屬性可以在多個(gè)地方賦值,xml定義,xml中引入style,theme中直接指定,defStyleAttr,defStyleRes?這5個(gè)地方。(后面會(huì)將這幾個(gè)地方的用處)

【第二個(gè)問(wèn)題】

屬性在多個(gè)地方被賦值后,系統(tǒng)以哪個(gè)屬性為準(zhǔn)呢?

我將用一個(gè)實(shí)驗(yàn),利用多個(gè)TextView整體說(shuō)明屬性賦值的優(yōu)先級(jí),這個(gè)實(shí)驗(yàn)將貫穿文章后面,我將分塊講解。

【實(shí)驗(yàn)】

首先我們定義一個(gè)style文件,從style中可以看出,我們定義了一個(gè)主題,主題中有兩種定義textView顏色的形式,一種是對(duì)textViewStyle進(jìn)行定義(藍(lán)色),一種是直接對(duì)textColor進(jìn)行定義(紫色)。這是主題運(yùn)用的兩種方式,后面詳述,現(xiàn)在我們只需要知道,我們的主題默認(rèn)不是白色的?。。?!

后面的幾種style,每種對(duì)應(yīng)一個(gè)顏色,用來(lái)區(qū)分優(yōu)先級(jí)。

【實(shí)驗(yàn) - style文件】

實(shí)驗(yàn)文件

【實(shí)驗(yàn) -布局文件】

我們聲明一個(gè)layout文件,里面有多個(gè)TextView和我自定義的View,現(xiàn)在我們自需要現(xiàn)在只看前三個(gè)TextView

布局文件

【實(shí)驗(yàn)結(jié)果】


結(jié)果

【實(shí)驗(yàn) -結(jié)果分析1】

我們現(xiàn)在只看前三個(gè)TextView

第一個(gè)由于主題的原因,是藍(lán)色

第二個(gè)style="@style/RedTextStyle",顏色是紅色,說(shuō)明優(yōu)先級(jí)style>theme

第三個(gè)style和xml定義同時(shí)存在,

style="@style/RedTextStyle

android:textColor="@android:color/holo_orange_light"

顯示橙色,說(shuō)明優(yōu)先級(jí)xml定義>style>theme

因此我們得到結(jié)論1:

【結(jié)論1】:優(yōu)先級(jí)xml定義>style>theme

【實(shí)驗(yàn) - 結(jié)果分析2】

但是theme的分析遠(yuǎn)沒(méi)有結(jié)束,我們剛才在定義主題時(shí),有兩個(gè)賦值,

文件

為什么TextView默認(rèn)的顏色是藍(lán)色,而非紫色呢?????

這就需要研究View是如何利用系統(tǒng)主題,這時(shí)候需要回到我們今天的主題:View的構(gòu)造函數(shù)?。。?!

View中如何體現(xiàn)主題的信息,需要就通過(guò)實(shí)驗(yàn)對(duì)View進(jìn)行徹底探究。這是一個(gè)復(fù)雜的問(wèn)題,需要看看View的第三和第四個(gè)構(gòu)造函數(shù),在看這兩個(gè)構(gòu)造函數(shù)時(shí),就不可避免的看到兩個(gè)讓人懵b的參數(shù):defStyleAttr和defStyleRes。這時(shí)引入我們的第三個(gè)問(wèn)題。

【第三個(gè)問(wèn)題】

那么在View的第四個(gè)構(gòu)造函數(shù)中的后面兩個(gè)的參數(shù)都是什么意思呢?

我們首先看看View的注釋?zhuān)?/p>

注釋

第四個(gè)構(gòu)造函數(shù)中第三個(gè)參數(shù)defStyleAttr,從名字就能看出,是一個(gè)屬性資源。

這個(gè)屬性資源跟主題有一個(gè)奇妙的協(xié)議:只要在主題中對(duì)這個(gè)屬性賦值,該View就會(huì)自動(dòng)應(yīng)用這個(gè)屬性的值。

再看看在第四個(gè)構(gòu)造函數(shù)中有一個(gè)參數(shù)defStyleRes,這個(gè)參數(shù)是什么作用呢?

先看注釋?zhuān)?/p>

注釋

這個(gè)參數(shù)說(shuō),只有在第三個(gè)參數(shù)defStyleAttr為0,或者主題中沒(méi)有找到這個(gè)defStyleAttr屬性的賦值時(shí),才可以啟用。而且這個(gè)參數(shù)不再是Attr了,而是真正的style。其實(shí)這也是一種低級(jí)別的“默認(rèn)主題”,即在主題未聲明屬性值時(shí),我們可以主動(dòng)的給一個(gè)style,使用這個(gè)構(gòu)造函數(shù)定義出的View,其主題就是這個(gè)定義的defStyleRes(是一種寫(xiě)死的style,因此優(yōu)先級(jí)被調(diào)低)。

【源碼實(shí)例】

我們看一下在TextView中是如何給defStyleAttr和defStyleRes這兩個(gè)參數(shù)賦值的。查看TextView的源碼中,四個(gè)構(gòu)造函數(shù):

構(gòu)造函數(shù)

可以看出,TextView的第2個(gè)構(gòu)造函數(shù)直接調(diào)用了第3個(gè)構(gòu)造函數(shù),只是傳了一個(gè)com.android.internal.R.attr.textViewStyle的參數(shù),第三個(gè)在調(diào)用第四個(gè)構(gòu)造函數(shù)時(shí),最后一個(gè)參數(shù)是0.

【TextView 的defStyleAttr和defStyleRes】

也就是說(shuō)在TextView中,TextView的第二個(gè)構(gòu)造函數(shù)傳入的defStyleAttrcom.android.internal.R.attr.textViewStyle

那么這個(gè)com.android.internal.R.attr.textViewStyle是個(gè)什么鬼呢,我們從源碼中看看。

查看/Sdk/platforms/android-23/data/res/values這個(gè)路徑中找個(gè)一個(gè)attrs.xml文件,打開(kāi)看看,找到textViewStyle,如下所示,哦,原來(lái)是一個(gè)reference類(lèi)型的屬性,因此在給這個(gè)屬性賦值時(shí),在xml中一般使用@style/xxx形式就可以了。

style

app的主題可以為這個(gè)textViewStyle屬性提供一套默認(rèn)的style資源。比如在本例中,我們的主題繼承自Theme.Holo中,在Theme.Holo中有一個(gè)item如下:

item

說(shuō)明在Theme.Holo中,textViewStyle指向@style/Widget.Holo.TextView

因此默認(rèn)情況下,TextView的屬性都是在Widget.Holo.TextView這個(gè)Style中(但是其實(shí)這個(gè)style中并沒(méi)有對(duì)textColor進(jìn)行定義,有興趣的可以自己去看看)。

在本例中我們自己定義了主題,通過(guò)繼承Theme.Holo主題,修改這個(gè)textViewStyle的reference,使得textViewStyle指向了藍(lán)色主題,如下所示。因此本文中app的TextView默認(rèn)顏色是藍(lán)色。

style

但是,我們的主題的內(nèi)容并沒(méi)有完結(jié),很明顯,我們?cè)谥黝}中還有一個(gè)android:textColor的賦值。

在同時(shí)使用了defStyleAttr(即主題中定義的textViewStyle)和主題直接定義時(shí),顯示了defStyleAttr的定義,說(shuō)明使用了defStyleAttr的優(yōu)先級(jí)要比直接在主題中聲明優(yōu)先級(jí)高。因此我們又得到一個(gè)結(jié)論。

【結(jié)論2】:優(yōu)先級(jí)defStyleAttr>theme直接定義

【第四個(gè)問(wèn)題】

從上文中我們知道了defStyleAttr和theme的順序,那么defStyleRes的優(yōu)先級(jí)呢?

現(xiàn)在需要確定defStyleRes的優(yōu)先級(jí)了,我們重新回到我們的實(shí)驗(yàn),我們的實(shí)驗(yàn)里,構(gòu)造了三種自定義的View, CustomView, CustomBlankView和CustomGreenView。

CustomView的代碼上面已寫(xiě),現(xiàn)在將剩下兩種自定義的View代碼展示如下:

【實(shí)驗(yàn) -CustemGreenView類(lèi)】


CustemGreenView

【實(shí)驗(yàn) -CustomBlankView類(lèi)】

CustomBlankView

【實(shí)驗(yàn)-結(jié)果分析3】

在CustomGreenView中,defStyleAttr被賦值為0,defStyleRes賦值為R.style.GreenTextStyle,即我們的綠色style。

在CustomBlankView中,defStyleAttr和defStyleRes都為0,此時(shí)的顏色是紫色,即直接在theme中聲明的顏色。

說(shuō)明在同時(shí)在defStyleRes和主題中聲明時(shí),優(yōu)先顯示defStyleRes.由此又得出一個(gè)結(jié)論。

【結(jié)論3】:優(yōu)先級(jí) defStyleRes>theme直接定義

在實(shí)驗(yàn)的最后兩個(gè)還是說(shuō)明了直接在xml中寫(xiě)屬性的優(yōu)先級(jí)較高,即

【結(jié)論4】:優(yōu)先級(jí)xml直接定義>xml的style定義>theme直接定義

【小結(jié)】

在Theme中的優(yōu)先級(jí)主要涉及到三個(gè)部分:defStyleAttr,defStyleRes和主題直接定義

我們需要分三種情況,在構(gòu)造函數(shù)中,

1?當(dāng)defStyleAttr!=0時(shí),

主題中如果對(duì)defStyleAttr屬性進(jìn)行賦值,顯示對(duì)defStyleAttr的賦值,優(yōu)先級(jí)最高!

2當(dāng)(defStyleAttr==0或主題沒(méi)有對(duì)defStyleAttr進(jìn)行賦值)&&?defStyleRes!=0而且theme中沒(méi)有定義時(shí)時(shí),顯示defStyleRes,優(yōu)先級(jí)中

3如果defStyleAttr==0且defStyleRes==0時(shí),顯示theme直接定義,優(yōu)先級(jí)最低

由此我們得到屬性賦值總體優(yōu)先級(jí):

【結(jié)論總】屬性賦值優(yōu)先級(jí)? Xml定義 > xml的style定義 >defStyleAttr> defStyleRes> theme直接定義

四 總結(jié)

在View類(lèi)中有四個(gè)構(gòu)造函數(shù),涉及到多個(gè)參數(shù),

Context:上線文,這個(gè)不用多說(shuō)

AttributeSet?attrs:從xml中定義的參數(shù)

intdefStyleAttr:主題中優(yōu)先級(jí)最高的屬性

intdefStyleRes:?優(yōu)先級(jí)次之的內(nèi)置于View的style

在android中的屬性可以在多個(gè)地方進(jìn)行賦值,涉及到的優(yōu)先級(jí)排序?yàn)椋?/p>

Xml直接定義?>?xml中style引用?>?defStyleAttr>defStyleRes?>?theme直接定義

總體來(lái)說(shuō),本文是對(duì)android中View的四個(gè)構(gòu)造函數(shù)的探究,主要涉及到View屬性的優(yōu)先級(jí)問(wèn)題。

叩謝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容