自定義View基礎(chǔ)之自定義屬性和構(gòu)造函數(shù)

自定義View分類

  • 繼承自View
    通常用于實(shí)現(xiàn)一些不規(guī)則的效果欢顷,這些效果不方便或者不能夠用布局組合的方式實(shí)現(xiàn)铺峭。這種自定義的View需要通過自定義繪制方式來實(shí)現(xiàn)墓怀,即重寫onDraw方法,需要注意的是卫键,注意wrap_content和padding兩個(gè)屬性的處理傀履。不做處理的話會(huì)導(dǎo)致這兩個(gè)參數(shù)失效
  • 繼承自ViewGroup
    主要用于實(shí)現(xiàn)自定義的布局,比如將幾個(gè)不同的View合并起來作為一個(gè)新的常用的Layout莉炉,使用的時(shí)候直接引入就會(huì)方便許多钓账。需要注意的是碴犬,ViewGroup和各個(gè)子元素的的Measure,Layout過程一定要處理好梆暮。
  • 繼承自特定的View
    這種方法比較常見服协,主要用于對(duì)現(xiàn)有View進(jìn)行擴(kuò)展,實(shí)現(xiàn)自己需要的特殊功能啦粹,而且實(shí)現(xiàn)起來相對(duì)簡(jiǎn)單偿荷,wrap_content和padding也不需要手動(dòng)處理
  • 繼承自特定ViewGroup
    這種方法也比較常見,而且不需要手動(dòng)處理ViewGroup的Measure唠椭,Layout過程跳纳,通常來說,繼承自ViewGroup能夠?qū)崿F(xiàn)的布局采用這種方式都能實(shí)現(xiàn)贪嫂,只不過直接繼承自ViewGroup更接近底層棒旗,靈活性也更好。

自定義View流程及常用方法解析

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

View的構(gòu)造函數(shù)有四種重載:

public void MyView(Context context) {}
public void MyView(Context context, AttributeSet attrs) {}
public void MyView(Context context, AttributeSet attrs, int defStyleAttr) {}
public void MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {}

常用到的只有第一第二兩種撩荣。第一個(gè)只有Context參數(shù)铣揉,在代碼中創(chuàng)建View時(shí),會(huì)調(diào)用此方法餐曹。
第二個(gè)有兩個(gè)參數(shù)逛拱,Context和AttributeSet,用在XML中創(chuàng)建View台猴,AttributeSet用來保存XML文件中View的各項(xiàng)屬性朽合。
后兩個(gè)參數(shù)的含義:
defStyleAttr參數(shù):這是一個(gè)定義在attrs.xml文件中的attribute。這個(gè)值起作用需要兩個(gè)條件:1. 值不為0饱狂;2. 在Theme中使用了(出現(xiàn)即可)曹步。
defStyleRes參數(shù): 這是在styles.xml文件中定義的一個(gè)style。只有當(dāng)defStyleAttr沒有起作用休讳,才會(huì)使用到這個(gè)值讲婚。
在分析這兩個(gè)參數(shù)的含義之前,我們先來了解一下View的屬性是怎樣設(shè)置的.

View的Style和Theme

首先俊柔,在XML文件中為View指定屬性有以下幾種方式:

  • 直接在layout中設(shè)置
  • 設(shè)置style筹麸,并在layout中指定Style
  • Application和Activity可以指定theme,在theme中設(shè)置當(dāng)前Application或者Activity的屬性默認(rèn)值雏婶。
        <EditText
        android:id="@+id/cusview_attrs"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        style="@style/MyTextStyle"
        android:text="simple image view"
        />

這是一個(gè)EditText物赶,我們?cè)趌ayout文件中設(shè)置了他的基本屬性,android:textSize="24sp"留晚,這個(gè)很容易理解酵紫。除此之外還有一個(gè)style="@style/MyTextStyle",這個(gè)Style是在values/style.xml文件中定義的:

        <style name="MyTextStyle" >
        <item name="android:textColor" >#00FF00</item>
        </style>

指定了一個(gè)顏色為綠色,可以看一下效果奖地,最終呈現(xiàn)出來的屬性就是24sp+綠色状蜗。
那么又有新的問題了,如果同時(shí)在屬性和Style中對(duì)同一屬性設(shè)置不同的值鹉动,結(jié)果會(huì)是怎樣的轧坎? 大家可以試一下,layout中直接指定的屬性優(yōu)先級(jí)高于Style泽示。
關(guān)于Style缸血,他還有一個(gè)parent父屬性,指定當(dāng)前Style是繼承自哪一個(gè)Style的:

        <style name="MyTextStyle" parent="@android:style/TextAppearence">
        <item name="android:textColor" >#00FF00</item>
        </style>

這表示我們自定義的MyTextStyle繼承了android:style/TextAppearence的默認(rèn)屬性械筛,同時(shí)指定textColor覆寫了父屬性捎泻。

介紹完了Style,現(xiàn)在我們?cè)賮砜匆幌耇heme是怎樣使用的埋哟。Style通常是針對(duì)某一個(gè)View進(jìn)行設(shè)置的笆豁,而theme針對(duì)的是Application和Activity。打開manifest文件赤赊,我們會(huì)看到以下的內(nèi)容:

 <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
......

Application會(huì)指定一個(gè)theme屬性闯狱,他的值在style中定義了:

 <!-- Application theme. -->
    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
    </style>

是完全繼承自AppBaseTheme的。就是說抛计,這個(gè)應(yīng)用的主題就是AppBaseTheme哄孤。當(dāng)然我們也可以自定義theme。

    <style name="MyAppTheme" parent="AppBaseTheme">
        <item name="android:background">#00FF00</item>
    </style>

這里設(shè)置了一個(gè)自定義的主題吹截,背景色為綠色瘦陈,將它應(yīng)用的某一個(gè)Activity:

<activity
            android:name=".MainActivity"
            android:label="@string/app_name" 
            android:configChanges="keyboardHidden|screenSize"
            android:theme="@style/MyAppTheme">
......

然后再運(yùn)行一下,看看效果你就會(huì)發(fā)現(xiàn)波俄,被指定的Activity整個(gè)都綠了晨逝。。懦铺。捉貌。
Android系統(tǒng)的theme.xml和style.xml存放位置在sdk\platforms\android-x\data\res\values下,感興趣的可以自己查看阀趴。

構(gòu)造函數(shù)的參數(shù)分析

我們看一下View的構(gòu)造函數(shù)源碼:

final TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);

View的各項(xiàng)屬性是context.obtainStyledAttributes方法來獲取的昏翰,他包含四個(gè)參數(shù)
第一苍匆,三刘急,四個(gè)參數(shù)很明顯,是從構(gòu)造函數(shù)里傳入的浸踩,第二個(gè)參數(shù)com.android.internal.R.styleable.View叔汁,表名了我們將要獲取的屬性。我們用一個(gè)例子來解釋,順便學(xué)習(xí)一下自定義參數(shù)的使用据块。
第一步码邻,在values下新建一個(gè)attrs.xml文件,這里定義好所需要的參數(shù)名稱和格式:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomizeView">
        <attr name="attr_1" format="string"/>
        <attr name="attr_2" format="string"/>
        <attr name="attr_3" format="string"/>
        <attr name="attr_4" format="string"/>
        <attr name="attr_5" format="string"/>
    </declare-styleable>
<attr name="CustomizeStyle" format="reference"/>
</resources>

這里我們定義了一個(gè)名稱為 MyCustomizeView 的styleable另假,他包含四項(xiàng)屬性 attr_1像屋,2 , 3, 4, 5,另外我們還定義了一個(gè)屬性CustomizeStyle边篮,他的類型是reference己莺,表示它可以接收一個(gè)style引用,各項(xiàng)屬性的值戈轿,可以在這個(gè)引用中定義凌受。

將屬性定義在styleable 中,和直接定義沒有很大的區(qū)別思杯,不管定義在哪個(gè)位置胜蛉,這些attribute都會(huì)生效,只是定義在styleable 中的styleable 色乾,系統(tǒng)會(huì)在R.styleable中生成相關(guān)屬性誊册。我們可以通過R.styleable.MyCustomizeView來引用他。 直接定義的暖璧,需要通過R.attr.CustomizeStyle來引用解虱。
各項(xiàng)屬性的使用方法如下:
在layout文件中使用:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myattrs="http://schemas.android.com/apk/com.training"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
        <com.training.view.MyCustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        myattrs:attr_1="Attr 1 set in layout "
        style="@style/MyStyle"
       />
</LinearLayout>

注意,要使用自定義屬性漆撞,必須新建一個(gè)自定義屬性的命名空間:

xmlns:名字="http://schemas.android.com/apk/res/包名"
或者xmlns:名字="http://schemas.android.com/apk/res-auto"

我們?cè)趯傩灾惺褂昧藄tyle殴泰,所以也要在style.xml中定義它:

     <style name="MyStyle">
        <item name="attr_1">attr 1 set in style </item>
        <item name="attr_2">attr 2 set in style </item>
    </style>

現(xiàn)在我們回到構(gòu)造函數(shù),

public void MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {}

后邊兩個(gè)參數(shù)怎樣使用呢浮驳? 開始的部分我們提到了:
defStyleAttr參數(shù):這是一個(gè)定義在attrs.xml文件中的attribute悍汛。這個(gè)值起作用需要兩個(gè)條件:1. 值不為0;2. 在Theme中使用了(出現(xiàn)即可)至会。
defStyleRes參數(shù): 這是在styles.xml文件中定義的一個(gè)style离咐。只有當(dāng)defStyleAttr沒有起作用,才會(huì)使用到這個(gè)值奉件。
defStyleAttr宵蛀,是定義在attrs.xml中的,在attrs中我們已經(jīng)定義了:

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

還要在Theme使用它县貌。代碼如下:

    <style name="AppTheme" parent="AppBaseTheme">
        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
        <item name="attr_1">attr 1 set in theme</item>
        <item name="attr_2">attr 2 set in theme</item>
        <item name="attr_3">attr 3 set in theme</item>
        <item name="CustomizeStyle">@style/StyleInTheme</item>
    </style>
    <style name="StyleInTheme">
        <item name="attr_1">attr 1 set in theme reference</item>
        <item name="attr_2">attr 2 set in theme reference</item>
        <item name="attr_3">attr 3 set in theme reference</item>
        <item name="attr_4">attr 4 set in theme reference</item>
    </style>

除此之外术陶,我們?cè)俣x一個(gè)style,對(duì)應(yīng)defStyleRes參數(shù)煤痕。

     <style name="DefaultCustomizeStyle">
    <item name="attr_1">attr 1 set in default style res</item>
    <item name="attr_2">attr 2 set in default style res</item>
    <item name="attr_3">attr 3 set in default style res</item>
    <item name="attr_4">attr 4 set in default style res</item>
    <item name="attr_5">attr 5 set in default style res</item>
    </style>

現(xiàn)在準(zhǔn)備工作已經(jīng)結(jié)束梧宫,我們做了以下工作:
1:定義了5個(gè)自定義屬性接谨,attr_1,2塘匣,3脓豪,4,它們接收String值忌卤,還有一個(gè)CustomizeStyle屬性扫夜,接收一個(gè)reference
2:在layout文件中直接給attr_1賦值了,另外還設(shè)置了一個(gè)MyStyle驰徊,在style中給attr_1历谍,2都進(jìn)行了賦值
3:在Application使用的theme中,直接對(duì)attr_1,2,3進(jìn)行賦值辣垒,同時(shí)設(shè)置了CustomizeStyle的引用對(duì)象望侈,在引用中對(duì)attr_1,2,3,4賦值。
4:設(shè)置了一個(gè)DefaultCustomizeStyle勋桶,對(duì)attr_1,2,3,4,5都進(jìn)行賦值脱衙。
現(xiàn)在我們看一下怎樣使用這些參數(shù):

public class MyCustomView extends View{
    private final String TAG = "ViewConstructor";
    public MyCustomView(Context context) {
        super(context);
    }
    public MyCustomView(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.CustomizeStyle);
    }
    public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, R.style.DefaultCustomizeStyle):      
    }
    public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomizeView, defStyleAttr, defStyleRes);
        String one = a.getString(R.styleable.MyCustomizeView_attr_1);
        String two = a.getString(R.styleable.MyCustomizeView_attr_2);
        String three = a.getString(R.styleable.MyCustomizeView_attr_3);
        String four = a.getString(R.styleable.MyCustomizeView_attr_4);
        String five = a.getString(R.styleable.MyCustomizeView_attr_5);
        Log.d(TAG, "ATTR_1------>" + one);
        Log.d(TAG, "ATTR_2------>" + two);
        Log.d(TAG, "ATTR_3------>" + three);
        Log.d(TAG, "ATTR_4------>" + four);
        Log.d(TAG, "ATTR_5------>" + five);
        a.recycle();
    }

現(xiàn)在運(yùn)行一下,就可以看到結(jié)果了:

ATTR_1------>Attr 1 set in layout
ATTR_2------>attr 2 set in style
ATTR_3------>attr 3 set in theme reference
ATTR_4------>attr 4 set in theme reference
ATTR_5------>null

attr_1在layout例驹,style捐韩,theme,theme的屬性引用鹃锈,defaultStyle中都賦值了荤胁,結(jié)果是layout中的賦值
attr_2在style,theme屎债,theme的屬性引用仅政,defaultStyle中賦值了,結(jié)果是style中的值
attr_3在theme盆驹,theme的屬性引用圆丹,defaultStyle中賦值了,結(jié)果是theme的屬性引用中的值
attr_4在theme的屬性引用躯喇,defaultStyle中賦值了辫封,結(jié)果是theme的屬性引用中的值
attr_5在defaultStyle中賦值了,結(jié)果是null廉丽。

也就是說倦微,他們的優(yōu)先級(jí)是這樣的:

直接在layout中定義>在style定義>defStyleAttr(在theme中,對(duì)屬性的引用賦值正压,對(duì)應(yīng)第三個(gè)參數(shù))>defStyleRes(設(shè)置默認(rèn)的style欣福,對(duì)應(yīng)第四個(gè)參數(shù))。
同時(shí)也印證了上文提到的蔑匣,defStyleRes參數(shù)只有當(dāng)defStyleAttr沒有起作用劣欢,才會(huì)使用到這個(gè)值棕诵。

如果將defStyleAttr設(shè)置為0:

    public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, 0, R.style.DefaultCustomizeStyle); 
    }

再運(yùn)行一下裁良,結(jié)果如下:

ATTR_1------>Attr 1 set in layout
ATTR_2------>attr 2 set in style
ATTR_3------>attr 3 set in default style res
ATTR_4------>attr 4 set in default style res
ATTR_5------>attr 5 set in default style res

這時(shí)候凿将,第四個(gè)參數(shù),defStyleRes終于起作用了价脾。

關(guān)于自定義參數(shù)的詳細(xì)說明牧抵,可以參考這位同學(xué)的文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市侨把,隨后出現(xiàn)的幾起案子犀变,更是在濱河造成了極大的恐慌,老刑警劉巖秋柄,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件获枝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡骇笔,警方通過查閱死者的電腦和手機(jī)省店,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笨触,“玉大人懦傍,你說我怎么就攤上這事÷樱” “怎么了粗俱?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)虚吟。 經(jīng)常有香客問我寸认,道長(zhǎng),這世上最難降的妖魔是什么串慰? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任废麻,我火速辦了婚禮,結(jié)果婚禮上模庐,老公的妹妹穿的比我還像新娘烛愧。我一直安慰自己,他們只是感情好掂碱,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布怜姿。 她就那樣靜靜地躺著,像睡著了一般疼燥。 火紅的嫁衣襯著肌膚如雪沧卢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天醉者,我揣著相機(jī)與錄音但狭,去河邊找鬼披诗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛立磁,可吹牛的內(nèi)容都是我干的呈队。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼唱歧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼宪摧!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起颅崩,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤几于,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后沿后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沿彭,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年尖滚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喉刘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡熔掺,死狀恐怖饱搏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情置逻,我是刑警寧澤推沸,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站券坞,受9級(jí)特大地震影響鬓催,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恨锚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一宇驾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猴伶,春花似錦课舍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至办桨,卻和暖如春筹淫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呢撞。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工损姜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饰剥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓摧阅,卻偏偏與公主長(zhǎng)得像汰蓉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逸尖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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