關(guān)于自定義view的構(gòu)造函數(shù)詳解

常見(jiàn)構(gòu)造方式:

在Android 中要使用一個(gè)view铛楣,通常會(huì)有兩種方式,1、xml中 2芳来、通過(guò)構(gòu)造函數(shù)new出一個(gè)指定的view對(duì)象。

/**
 * 關(guān)于view構(gòu)造參數(shù)的詳解
 */
public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    LinearLayout container = (LinearLayout) findViewById(R.id.activity_main);
    /**
     * 一個(gè)參數(shù)的構(gòu)造函數(shù)
     */
    Button buttonOne = new Button(this);
    buttonOne.setText("(Context)");

    /**
     * 三個(gè)參數(shù)的構(gòu)造函數(shù)
     */
    Button buttonThree = new Button(this, null, 0);
    buttonThree.setText("(Context,AttributeSet,0)");

    container.addView(buttonOne);
    container.addView(buttonThree);
  }
}
展示效果如圖所示

顯然使用三個(gè)構(gòu)造函數(shù)生成的button猜拾,樣式不正確而且無(wú)法完成點(diǎn)擊

View的構(gòu)造函數(shù):

通用構(gòu)造函數(shù)展示如下:
  public View(Context context);  

  public View(Context context, AttributeSet attrs);  

  public View(Context context, AttributeSet attrs, int defStyle);  

關(guān)于button的構(gòu)造函數(shù)展示如下:

public class Button extends TextView {  
  public Button(Context context) {  
    this(context, null);  
  }  

  public Button(Context context, AttributeSet attrs) {  
    this(context, attrs, com.android.internal.R.attr.buttonStyle);  
  }  

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

Button 繼承自 TextView即舌,顯然由構(gòu)造函數(shù)我們可知,二者的區(qū)分主要來(lái)自com.android.internal.R.attr.buttonStyle這第三個(gè)參數(shù)挎袜。

View構(gòu)造方法中的第三個(gè)參數(shù):

  • 用來(lái)給View提供一個(gè)基本的style顽聂,如果我們沒(méi)有對(duì)view設(shè)置某些屬性,就使用這個(gè)style的屬性盯仪。

通過(guò)三個(gè)參數(shù)的構(gòu)造函數(shù)紊搪,進(jìn)入TextView中查看構(gòu)造方法,當(dāng)中有一句關(guān)鍵代碼如下全景,:

TypedArray a = theme.obtainStyledAttributes(attrs,
            com.android.internal.R.styleable.TextViewAppearance, defStyleAttr, defStyleRes);

obtainStyledAttributes方法介紹:

public TypedArray obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)  
  • set:在XML中明確寫(xiě)出的屬性集合耀石。(比如:android:layout_width 等)
  • attrs:需要我們?cè)谏厦娴膕et集合中查詢(xún)哪些內(nèi)容,如果是自定義view爸黄,一般我們會(huì)把自定義的屬性寫(xiě)在declare-styleable中滞伟,代表我們想要查詢(xún)這些自定義屬性。
  • defStyleAttr:這是一個(gè)定義在attrs.xml文件中的attribute 這個(gè)值起作用需要兩個(gè)條件:1炕贵、值不為0 2梆奈、在Theme中出現(xiàn)過(guò)(出現(xiàn)即可)
  • defStyleRes:這是在styles.xml文件中定義的一個(gè)style。只有當(dāng)defStyleAttr沒(méi)有起作用称开,才會(huì)使用到這個(gè)值亩钟。

顯然,一個(gè)屬性最終的取值鳖轰,是有一個(gè)順序的問(wèn)題清酥,這個(gè)順序的優(yōu)先級(jí)從高到低依次是:

1、直接中在XML文件中定義蕴侣。
2焰轻、在XML文件中通過(guò)style這個(gè)屬性定義。
3睛蛛、通過(guò)defStyleAttr定義鹦马。
4胧谈、通過(guò)defStyleRes定義忆肾。
5、直接在當(dāng)前工程的theme主題下定義菱肖。

關(guān)于com.android.internal.R.attr.buttonStyle 這個(gè)位于客冈,frameworks\base\core\res\res\values\attrs.xml 中:

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

只是定義了一個(gè)引用,在theme.xml文件下稳强,有這樣一個(gè)style:

<style name="Theme">  
...  
   <item name="buttonStyle">@android:style/Widget.Button</item>  
...  
</style>  

在這里使用到了buttonStyle屬性场仲,它指向另外一個(gè)style和悦,這個(gè)style在styles.xml文件下:

<style name="Widget.Button">  
    <item name="android:background">@android:drawable/btn_default</item>  
    <item name="android:focusable">true</item>  
    <item name="android:clickable">true</item>  
    <item name="android:textAppearance">?android:attr/textAppearanceSmallInverse</item>  
    <item name="android:textColor">@android:color/primary_text_light</item>  
    <item name="android:gravity">center_vertical|center_horizontal</item>  
</style>  

這些屬性都是用來(lái)配置Button的,如果在XML文件中沒(méi)有給Button配置背景渠缕、內(nèi)容的位置等屬性們就會(huì)默認(rèn)的使用這里的屬性鸽素。當(dāng)前這是在使用了defStyleAttr的情況下才會(huì)出現(xiàn)的。

上面的themes.xml中的那個(gè)style的名稱(chēng)為T(mén)heme亦鳞,而在我們自己的工程中馍忽,在配置menifest文件的時(shí)候,給application或者activity設(shè)置的主題android:theme一般都是這個(gè)style的子類(lèi)燕差,所以也就這樣使用到了defStyleAttr定義的屬性了

還有一個(gè)defStyleRes參數(shù)遭笋,我們可以發(fā)現(xiàn)在TextView、ImageView等控件中徒探,這個(gè)值傳的都是0瓦呼,也就是不使用它。它的作用就像是一個(gè)替補(bǔ)测暗,當(dāng)defStyleAttr不起作用的時(shí)候它就上場(chǎng)央串,因?yàn)樗彩且粋€(gè)style,這個(gè)參數(shù)是怎么起作用的在下面的實(shí)例中有提到碗啄。

public class DefineView extends View {
  static final String LOG_TAG = "DefineView";
  public DefineView(Context context) {
    this(context, null);
  }

  public DefineView(Context context, AttributeSet attrs) {
    /**
     * 在style中蹋辅,theme style中建立對(duì)應(yīng)的attrs和style之間的對(duì)應(yīng)關(guān)系
     */
    this(context, attrs, R.attr.defineViewStyle);
  }

  public DefineView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    /**
     * 打印各個(gè)屬性的值
     */
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DefineView, defStyleAttr, 0);
    Log.d(LOG_TAG, "attr1 => " + array.getString(R.styleable.DefineView_attr1));
    Log.d(LOG_TAG, "attr2 => " + array.getString(R.styleable.DefineView_attr2));
    Log.d(LOG_TAG, "attr3 => " + array.getString(R.styleable.DefineView_attr3));
    Log.d(LOG_TAG, "attr4 => " + array.getString(R.styleable.DefineView_attr4));
    Log.d(LOG_TAG, "attr5 => " + array.getString(R.styleable.DefineView_attr5));
    Log.d(LOG_TAG, "attr6 => " + array.getString(R.styleable.DefineView_attr6));
    Log.d(LOG_TAG, "attr6 => " + array.getString(R.styleable.DefineView_attr7));

  }
}

<com.example.leiiiooo92.defineview.DefineView
    style="@style/xml_style"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:attr1="attr1 from xml"
    app:attr2="attr2 from xml" />

<resources>
  <!--定義自定義view的屬性-->
  <declare-styleable name="DefineView">
    <attr name="attr1" format="string" />
    <attr name="attr2" format="string" />
    <attr name="attr3" format="string" />
    <attr name="attr4" format="string" />
    <attr name="attr5" format="string" />
    <attr name="attr6" format="string" />
    <attr name="attr7" format="string" />
  </declare-styleable>

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

</resources>

<resources>

  <!-- Base application theme. -->
  <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>
    <!--綁定attrs和style中對(duì)應(yīng)項(xiàng)的關(guān)系-->
    <item name="defineViewStyle">@style/define_view_style</item>
  </style>
  <!-- 首先定義我們的defStyleAttr屬性(在本項(xiàng)目中是defineViewStyle屬性)需要用到的style(位于styles.xml文件中) -->
  <style name="define_view_style">
    <item name="attr3">attr3 from define_view_style</item>
    <item name="attr4">attr4 from define_view_style</item>
  </style>
  <!-- 定義一個(gè)在xml布局中需要使用到的style -->
  <style name="xml_style">
    <item name="attr2">attr2 from xml_style</item>
    <item name="attr3">attr3 from xml_style</item>
  </style>
</resources>
未設(shè)置defStyleAttr時(shí)

分析:
attr1只在xml布局文件中設(shè)置,所以值為attr1 from xml挫掏。
attr2在xml布局文件和xml style中都設(shè)置了侦另,取值為布局文件中設(shè)置的值,所以為attr2 from xml尉共。
attr3沒(méi)有在xml布局文件中設(shè)置褒傅,但是在xml style和defStyleAttr定義的style中設(shè)置了,取xml style中的值袄友,所以值為attr3 from xml_style殿托。
attr4只在defStyleAttr定義的style中設(shè)置了,所以值為attr4 from custom_view_style剧蚣。

下面測(cè)試一下defStyleRes這個(gè)參數(shù)支竹,它是一個(gè)style

<style name="define_view_res_style">  
  <item name="attr4">attr4 from define_view_res_style</item>  
  <item name="attr5">attr5 from define_view_res_style</item>  
</style> 

當(dāng)defStyleAttr這個(gè)參數(shù)定義為0(即不使用這個(gè)參數(shù)),或者是在theme中找不到defStyleAttr這個(gè)屬性時(shí)(即使在theme中的配置是這樣的:<item name="defStyleAttr">@null</item>鸠按,也代表找到了defStyleAttr屬性礼搁,defStyleRes參數(shù)也不會(huì)生效),defStyleRes參數(shù)才會(huì)生效目尖。

修改對(duì)應(yīng)的獲取自定義屬性語(yǔ)句:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DefineView, 0, R.style.define_view_res_style);
設(shè)置defStyleAttr時(shí)

由于defStyleAttr已經(jīng)失效馒吴,所以attr4和attr5都是從define_view_res_style中獲取到的值。

在主題中添加指定的屬性值:

<item name="attr5">attr5 from AppTheme</item>  
<item name="attr6">attr6 from AppTheme</item>  
主題中添加對(duì)應(yīng)的屬性值

attr5在define_view_res_style和theme下都定義了,取define-res-style下的值饮戳,所以為attr5 from define_view_res_style豪治。
attr6只在theme下定義了,所以取值為attr6 from AppTheme扯罐。

當(dāng)未設(shè)置def-res-style時(shí)负拟,主題中的屬性是否生效:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DefineView, defStyle, 0);
QQ截圖20161031183605.png

總結(jié):

View中的屬性有多處地方可以設(shè)置值,這個(gè)優(yōu)先級(jí)是:
1歹河、直接在XML布局文件中設(shè)置的值優(yōu)先級(jí)最高齿椅,如果這里設(shè)置了值,就不會(huì)去取其他地方的值了启泣。
2涣脚、XML布局文件中有一個(gè)叫“style”的屬性,它指向一個(gè)style寥茫,在這個(gè)style中設(shè)置的屬性值優(yōu)先級(jí)次之遣蚀。
3、如果上面兩個(gè)地方都沒(méi)有設(shè)置值纱耻,那么就會(huì)根據(jù)View帶三個(gè)參數(shù)的構(gòu)造方法中的第三個(gè)參數(shù)attribute指向的style設(shè)置值芭梯,前提是這個(gè)attribute的值不為0。
4弄喘、如果上面的attribute設(shè)置為0了玖喘,我們就根據(jù)obtainStyledAttributes()方法中的最后一個(gè)參數(shù)指向的style來(lái)設(shè)置值。
5蘑志、如果仍然沒(méi)有設(shè)置到值累奈,就會(huì)用theme中直接設(shè)置的屬性值,而不會(huì)去管第3步和第4步中是否設(shè)置了值急但。

必須要注意:要想讓View構(gòu)造方法的第三個(gè)參數(shù)生效澎媒,必須讓它出現(xiàn)在我們自己的Application或者Activity的android:theme所指向的style中。設(shè)置Activity的theme一樣可以波桩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末戒努,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子镐躲,更是在濱河造成了極大的恐慌储玫,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萤皂,死亡現(xiàn)場(chǎng)離奇詭異撒穷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)敌蚜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)桥滨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人弛车,你說(shuō)我怎么就攤上這事齐媒。” “怎么了纷跛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵喻括,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我贫奠,道長(zhǎng)唬血,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任唤崭,我火速辦了婚禮拷恨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘谢肾。我一直安慰自己腕侄,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布芦疏。 她就那樣靜靜地躺著冕杠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酸茴。 梳的紋絲不亂的頭發(fā)上分预,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音薪捍,去河邊找鬼笼痹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酪穿,可吹牛的內(nèi)容都是我干的与倡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼昆稿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼纺座!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起溉潭,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤净响,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后喳瓣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體馋贤,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年畏陕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了配乓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖犹芹,靈堂內(nèi)的尸體忽然破棺而出崎页,到底是詐尸還是另有隱情,我是刑警寧澤腰埂,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布飒焦,位于F島的核電站,受9級(jí)特大地震影響屿笼,放射性物質(zhì)發(fā)生泄漏牺荠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一驴一、第九天 我趴在偏房一處隱蔽的房頂上張望休雌。 院中可真熱鬧,春花似錦肝断、人聲如沸杈曲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鱼蝉。三九已至,卻和暖如春箫荡,著一層夾襖步出監(jiān)牢的瞬間魁亦,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工羔挡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洁奈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓绞灼,卻偏偏與公主長(zhǎng)得像利术,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子低矮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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