Drawable Resources與Color State List Resource

概述

Android把任何可繪制在屏幕上的圖形圖像都稱為drawable 資源,你可以通過類似getDrawable(int)的API來獲取drawable資源,你也可以通過類似android:drawable 章鲤、 android:icon的屬性將drawable 資源應(yīng)用到其他的XML資源中旦签。Drawable表示的是一種可以在Canvas上進(jìn)行繪制的抽象的概念朴上、它的種類有很多,它們都表示一種圖像的概念铝阐,通過圖片或者顏色可以構(gòu)造出各式各樣的圖像的效果恨胚,也可以通過繼承Drawable類自定義Drawable來構(gòu)建圖像的效果。
我們經(jīng)常會(huì)接觸到的drawable: state list drawable灼卢、shape drawable绍哎、 layer list drawable、ripple drawable鞋真、inset drawable以及nine patch drawable崇堰。前5個(gè)drawable通常定義在XML布局文件中,因此我們統(tǒng)一將它們歸屬為XML drawable類別涩咖。這6中常用的drawable與Drawable類之間的關(guān)系如下圖所示:


Drawable類繼承關(guān)系圖

下面我會(huì)講解上面提到的六種常用的Drawable和Color State List Resource海诲,最后再講解一下自定義Drawable。

預(yù)備知識(shí)

1 關(guān)于Image Dithering(圖像抖動(dòng))的介紹
Image Dithering(圖像抖動(dòng)) 是 Dithering(抖動(dòng))在數(shù)字圖片處理中的一種應(yīng)用檩互。一般情況下是指一種使數(shù)字圖片在降低色深的情況下特幔,呈現(xiàn)最佳展現(xiàn)的技術(shù)。比如將24bit色深的圖像使用8bit色深來展現(xiàn)闸昨。
例圖:


原圖

原圖降低色深蚯斯,沒有加抖動(dòng)處理

原圖降低色深,加抖動(dòng)處理

圖像抖動(dòng)技術(shù)常用的算法是 Floyd–Steinberg dithering.
編程應(yīng)用: 在Android應(yīng)用開發(fā)中饵较,使用 android:dither 屬性來設(shè)置圖像是否應(yīng)用抖動(dòng)處理拍嵌。

幾種常用的XML drawable

1 shape drawable
使用XML文件來定義幾何圖形,可以理解為通過顏色來構(gòu)造的幾何圖形循诉,它既可以是純色的幾何圖形横辆,也可以是具有漸變效果的幾何圖形。對(duì)應(yīng)GradientDrawable類茄猫。

file location:
    res/drawable/filename.xml
    The filename is used as the resource ID.
compiled resource datatype:
    Resource pointer to a GradientDrawable.
resource reference:
    In Java: R.drawable.filename
In XML: @[package:]drawable/filename

語法:

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape=["rectangle" | "oval" | "line" | "ring"] >
    <corners
        android:radius="integer"
        android:topLeftRadius="integer"
        android:topRightRadius="integer"
        android:bottomLeftRadius="integer"
        android:bottomRightRadius="integer" />
    <gradient
        android:angle="integer"
        android:centerX="float"
        android:centerY="float"
        android:centerColor="integer"
        android:endColor="color"
        android:gradientRadius="integer"
        android:startColor="color"
        android:type=["linear" | "radial" | "sweep"]
        android:useLevel=["true" | "false"] />
    <padding
        android:left="integer"
        android:top="integer"
        android:right="integer"
        android:bottom="integer" />
    <size
        android:width="integer"
        android:height="integer" />
    <solid
        android:color="color" />
    <stroke
        android:width="integer"
        android:color="color"
        android:dashWidth="integer"
        android:dashGap="integer" />
</shape>

1.1 <shape>節(jié)點(diǎn)元素
該節(jié)點(diǎn)元素一定被用作根元素狈蚤。
<shape>節(jié)點(diǎn)元素的常用屬性:
1> android:shape
定義shape drawable的類型,可用的有效值如下:

Value Desciption
"rectangle" A rectangle that fills the containing View. This is the default shape.
"oval" An oval shape that fits the dimensions of the containing View.
"line" A horizontal line that spans the width of the containing View. This shape requires the <stroke> element to define the width of the line.
"ring" A ring shape.

line和ring這兩個(gè)類型必須要通過stroke節(jié)點(diǎn)元素來指定線的寬度和顏色等信息募疮,否者無法達(dá)到預(yù)期的顯示效果炫惩。
2> 只有當(dāng)android:shape="ring"時(shí),以下的屬性才被使用:

android:innerRadius
Dimension 內(nèi)環(huán)的半徑阿浓,可直接使用尺寸值或者引用尺寸資源他嚷。

android:innerRadiusRatio
Float 內(nèi)環(huán)半徑與環(huán)寬度的比例。例如芭毙,如果android:innerRadiusRatio="5"筋蓖,則內(nèi)環(huán)半徑等于drawable寬度的5分之1,這個(gè)值會(huì)被android:innerRadius屬性值重寫退敦。默認(rèn)值為3猾漫。

android:thickness
Dimension 環(huán)的厚度,可直接使用尺寸值或者引用尺寸資源玖雁。

android:thicknessRatio
Float 環(huán)的厚度與環(huán)寬度的比例。例如翰铡,如果android:thicknessRatio="2",則環(huán)的厚度等于drawable的寬度除以2讽坏。這個(gè)值會(huì)被android:innerRadius屬性值重寫锭魔。默認(rèn)值是9。

android:useLevel
Boolean 一般都應(yīng)該使用false路呜,否者有可能無法達(dá)到預(yù)期的顯示效果迷捧,除非它被當(dāng)做LevelListDrawable來使用。

1.2 <corners>節(jié)點(diǎn)元素
用來為shape drawable創(chuàng)建圓角胀葱,僅適用于shape drawable是矩形時(shí)漠秋,即只有<shape>節(jié)點(diǎn)中android:shape屬性為rectangle時(shí)。
<corners>節(jié)點(diǎn)元素的常用屬性:

android:radius
Dimension 所有圓角的半徑抵屿,可直接使用尺寸值或者引用尺寸資源庆锦。每一個(gè)圓角的半徑值會(huì)被如下的屬性值重寫。

android:topLeftRadius
Dimension 左上圓角的半徑轧葛,可直接使用尺寸值或者引用尺寸資源肥荔。

android:topRightRadius
Dimension 右上圓角的半徑,可直接使用尺寸值或者引用尺寸資源朝群。

android:bottomLeftRadius
Dimension 左下圓角的半徑燕耿,可直接使用尺寸值或者引用尺寸資源。

android:bottomRightRadius
Dimension 右下圓角的半徑姜胖,可直接使用尺寸值或者引用尺寸資源誉帅。

注意:圓角的半徑必須大于1,否則沒有圓角右莱。如果你想要指定某個(gè)角不是圓角蚜锨,一個(gè)解決方法是使用android:radius屬性去給圓角半徑設(shè)置一個(gè)大于1的默認(rèn)值,然后重寫你不想是圓角的對(duì)應(yīng)屬性值為0dp亚再。

1.3 <gradient>節(jié)點(diǎn)元素
為shape drawable指定一種漸變顏色。它與<solid>節(jié)點(diǎn)元素是互相排斥的晨抡,其中solid表示純色填充氛悬,而gradient則表示漸變效果。
<gradient>節(jié)點(diǎn)元素的常用屬性:

android:angle
Integer 顏色漸變的方向耘柱,0 is left to right, 90 is bottom to top.必須是45的倍數(shù). Default is 0.

android:type
Keyword 漸變圖案的類型如捅,可用的有效值如下:
android:startColor
Color顏色漸變的開始顏色,為十六進(jìn)制顏色值值或者引用Color資源调煎。

android:endColor
Color顏色漸變的結(jié)束顏色镜遣,為十六進(jìn)制顏色值值或者引用Color資源。

android:centerColor
Color顏色漸變的中間顏色士袄,為十六進(jìn)制顏色值或者引用Color資源悲关。

android:centerX
Float (0 - 1.0) 相對(duì)X的漸變位置谎僻,默認(rèn)值為0.5。在type為linear時(shí)而且只有centerColor被設(shè)置時(shí)該屬性才會(huì)起作用寓辱。

android:centerY
Float (0 - 1.0) 相對(duì)Y的漸變位置戈稿,默認(rèn)值為0.5。在type為linear時(shí)而且只有centerColor被設(shè)置時(shí)該屬性才會(huì)起作用讶舰。

android:gradientRadius
Float 漸變的半徑,單位應(yīng)該是像素點(diǎn). 僅當(dāng)android:type="radial"時(shí)有效.

android:useLevel
Boolean 一般為false需了,當(dāng)Drawable作為L(zhǎng)evelListDrawable使用時(shí)為true.

舉例說明:
例一:
顏色從透明到不透明漸變跳昼。



運(yùn)行結(jié)果如下:



例二:

運(yùn)行結(jié)果如下:

例三:



運(yùn)行結(jié)果如下:

例四:

運(yùn)行結(jié)果如下:

例五:

運(yùn)行結(jié)果如下:

1.4 <solid>節(jié)點(diǎn)元素
這個(gè)節(jié)點(diǎn)元素表示純色填充,通過android:color即可指定shape drawable中填充的顏色肋乍。

1.5 <stroke>節(jié)點(diǎn)元素
描邊鹅颊。
<stroke>節(jié)點(diǎn)元素的常用屬性:

android:width="2dp"   描邊的寬度。
android:color   描邊的顏色墓造。

我們還可以把描邊弄成虛線的形式堪伍,設(shè)置方式為:
android:dashWidth="5dp"   表示'-'這樣一個(gè)橫線的寬度.
android:dashGap="3dp"     表示'-'之間隔開的距離。

1.6 <padding>節(jié)點(diǎn)元素
用來設(shè)置包含該shape drawable的View的padding
<padding>節(jié)點(diǎn)元素的常用屬性:

android:left
Dimension  Left padding觅闽,可直接使用尺寸值或者引用尺寸資源帝雇。

android:top
Dimension  Top padding,可直接使用尺寸值或者引用尺寸資源蛉拙。

android:right
Dimension  Right padding尸闸,可直接使用尺寸值或者引用尺寸資源。

android:bottom
Dimension  Bottom padding孕锄,可直接使用尺寸值或者引用尺寸資源吮廉。

1.7 <size>節(jié)點(diǎn)元素
shape drawable的固有大小。
<size>節(jié)點(diǎn)元素的常用屬性:

android:height
Dimension  shape drawable的固有高度畸肆,可直接使用尺寸值或者引用尺寸資源宦芦。

android:width
Dimension  shape drawable的固有寬度,可直接使用尺寸值或者引用尺寸資源轴脐。

上面的兩個(gè)屬性表示的是shape drawable的固有寬高调卑,但是一般來說它并不是shape drawable最終顯示的寬高,這個(gè)有點(diǎn)抽象大咱,但是我們要明白令野,對(duì)于shape drawable來說它并沒有寬高的概念,作為View的背景shape drawable會(huì)自適應(yīng)View的寬高徽级。我們知道Drawable的兩個(gè)方法getIntrisicWidth和getIntrinsicHeight表示的是Drawable的固有寬高气破,對(duì)于有些Drawable比如BitmapDrawable,它的固有寬高就是圖片的尺寸餐抢;而對(duì)于shape drawable來說现使,默認(rèn)情況下他是沒有固有寬高的概念的低匙,這個(gè)時(shí)候方法getIntrisicWidthhe和getIntrinsicHeight會(huì)返回-1,但是如果通過<size>標(biāo)簽來指定寬高信息碳锈,那么這個(gè)時(shí)候shape drawable就有了所謂的固有寬高顽冶;因此,總結(jié)來說售碳,<size>標(biāo)簽設(shè)置的寬高就是shape drawable的固有寬高强重,但是作為View的背景時(shí),shape drawable還會(huì)被拉伸或者縮小為View的大小贸人。

2 inset drawable
當(dāng)一個(gè)View希望自己的背景比自己的實(shí)際區(qū)域小的時(shí)候间景,這非常有用。對(duì)應(yīng)InsetDrawable類艺智。

file location:
    res/drawable/filename.xml
    The filename is used as the resource ID.
compiled resource datatype:
    Resource pointer to a InsetDrawable.
resource reference:
    In Java: R.drawable.filename
    In XML: @[package:]drawable/filename 

語法:

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:insetTop="dimension"
    android:insetRight="dimension"
    android:insetBottom="dimension"
    android:insetLeft="dimension" />

2.1 <inset>節(jié)點(diǎn)元素:
<inset>節(jié)點(diǎn)元素的常用屬性:

android:drawable:
    Drawable resource. Required. Reference to a drawable resource to be inset.
android:insetTop
    Dimension. inset drawable與使用該inset drawable的View的頂部距離, as a dimension value or dimension resource
android:insetRight
    Dimension. inset drawable與使用該inset drawable的View的右邊距離, as a dimension value or dimension resource
android:insetBottom
    Dimension. inset drawable與使用該inset drawable的View的底部距離, as a dimension value or dimension resource
android:insetLeft
    Dimension. inset drawable與使用該inset drawable的View的左邊距離, as a dimension value or dimension resource

3 layer list drawable
layer list drawable是一個(gè)管理著一個(gè)Drawable對(duì)象數(shù)組的LayerDrawable類的對(duì)象倘要,數(shù)組中的每一個(gè)Drawable對(duì)象按照下標(biāo)的順序進(jìn)行繪制,因此數(shù)組中的最后一個(gè)Drawable對(duì)象被繪制在最上面十拣。
每一個(gè)Drawable是通過一個(gè)<item>元素來表示封拧,每一個(gè)<item>元素都定義在<layer-list> 元素中。

FILE LOCATION:
    res/drawable/filename.xml
    The filename is used as the resource ID.
COMPILED RESOURCE DATATYPE:
    Resource pointer to a LayerDrawable.
RESOURCE REFERENCE:
    In Java: R.drawable.filename
    In XML: @[package:]drawable/filename

語法:

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:drawable="@[package:]drawable/drawable_resource"
        android:id="@[+][package:]id/resource_name"
        android:top="dimension"
        android:right="dimension"
        android:bottom="dimension"
        android:left="dimension" />
</layer-list>

一個(gè)layer list drawable中可以包含多個(gè)item夭问,每個(gè)item表示一個(gè)Drawable泽西。item的結(jié)構(gòu)比較簡(jiǎn)單,比較常用的屬性有android:top缰趋、android:right尝苇、android:bottom和android:left,他們分別表示Drawable相對(duì)于View的上下左右的偏移量埠胖,單位為像素糠溜。另外,我們可以通過android:drawable來引用一個(gè)已有的Drawable資源直撤,當(dāng)然也可以在item中自定義Drawable非竿。

4 ripple drawable
該drawable是在api21(L)時(shí)被引進(jìn)的,可以實(shí)現(xiàn)觸摸反饋的效果(波浪的效果)谋竖。對(duì)應(yīng)RippleDrawable類红柱,繼承LayerDrawable(即繼承l(wèi)ayer list drawable的所有特點(diǎn))。

4.1 針對(duì)ImageView的background屬性
下面三個(gè)例子是針對(duì)ImageView的background屬性的:
對(duì)于三個(gè)例子的總結(jié)(針對(duì)background屬性):
波浪最大區(qū)域是該View的外接圓

例一 If no child layers or mask is specified and the ripple is set as a View background , the ripple will be drawn atop the first available parent background within the View's hierarchy. In this case, the drawing region may extend outside of the Drawable bounds.
我的翻譯 :在ripple中沒有item子節(jié)點(diǎn)或者包含有一個(gè)id被指定為@android:id/mask的item并且將該ripple drawable設(shè)置為View的background屬性值時(shí)蓖乘,波浪動(dòng)畫將會(huì)繪制在視圖層級(jí)結(jié)構(gòu)中第一個(gè)可見的該View的父視圖之上锤悄,在這種情況下,波浪動(dòng)畫可能會(huì)越過View區(qū)域嘉抒,波浪動(dòng)畫最大區(qū)域是該View區(qū)域的外接圓零聚,但是不會(huì)超過第一個(gè)可見父視圖的區(qū)域。

舉例代碼如下:

/TestDrawable/res/layout/fragment_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layout_margin="30dp"
        android:background="@drawable/beauty2" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/iv_background"
            android:clickable="true"
            android:layout_marginTop="30dp"
            android:padding="30dp"
            android:src="@drawable/beauty4" />
    </LinearLayout>

</LinearLayout>

/TestDrawable/res/drawable/iv_background1.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff00ff00" >

</ripple>

運(yùn)行結(jié)果如下:


例二
在例一的基礎(chǔ)上在ripple根節(jié)點(diǎn)上添加一個(gè)item項(xiàng),相當(dāng)于ripple drawable當(dāng)前擁有一個(gè)Drawable圖層并且當(dāng)將該ripple drawable設(shè)置為View的background屬性值時(shí)該Drawable圖層可以限制波浪動(dòng)畫不會(huì)越過View區(qū)域隶症,波浪動(dòng)畫將被繪制在該View區(qū)域上政模,在這種情況下,波浪動(dòng)畫不會(huì)越過View區(qū)域蚂会,波浪最大區(qū)域是該View區(qū)域的外接圓淋样,但是波浪動(dòng)畫不會(huì)越過View區(qū)域。

舉例代碼如下:

/TestDrawable/res/layout/fragment_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layout_margin="30dp"
        android:background="@drawable/beauty2" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/iv_background2"
            android:clickable="true"
            android:layout_marginTop="30dp"
            android:padding="30dp"
            android:src="@drawable/beauty4" />
    </LinearLayout>

</LinearLayout>

/TestDrawable/res/drawable/iv_background2.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff00ff00" >

    <item android:drawable="@android:color/black"/>

</ripple>

運(yùn)行結(jié)果如下:


例三
在例二中添加的item節(jié)點(diǎn)中添加android:id="@android:id/mask"胁住,相當(dāng)于當(dāng)將該ripple drawable設(shè)置為View的background屬性值時(shí)該item節(jié)點(diǎn)定義的Drawable圖層僅僅是用來限制波浪動(dòng)畫不會(huì)越過View區(qū)域趁猴。波浪動(dòng)畫將被繪制在該View區(qū)域上,在這種情況下彪见,波浪動(dòng)畫不會(huì)越過View區(qū)域儡司,波浪最大區(qū)域是該View區(qū)域的外接圓,但是波浪動(dòng)畫不會(huì)超過View區(qū)域企巢。
舉例代碼如下:

/TestDrawable/res/layout/fragment_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="30dp"
        android:background="@drawable/beauty2"
        android:orientation="vertical" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/iv_background3"
            android:clickable="true"
            android:layout_marginTop="30dp"
            android:padding="30dp"
            android:src="@drawable/beauty4" />
    </LinearLayout>

</LinearLayout>

/TestDrawable/res/drawable/iv_background3.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff00ff00" >

    <item android:id="@android:id/mask"
        android:drawable="@android:color/black"/>

</ripple>

運(yùn)行結(jié)果如下:


4.2 針對(duì)ImageView的src屬性的

下面三個(gè)例子是針對(duì)ImageView的src屬性的:
對(duì)于三個(gè)例子的總結(jié)(針對(duì)src屬性):
波浪最大區(qū)域是該View內(nèi)容的外接圓

例一:
在ripple中沒有item子節(jié)點(diǎn)或者包含有一個(gè)id被指定為@android:id/mask的item并且將該ripple drawable設(shè)置為View的src屬性值時(shí),波浪動(dòng)畫將會(huì)繪制在該View區(qū)域上让蕾,在這種情況下浪规,波浪動(dòng)畫可能會(huì)越過View內(nèi)容區(qū)域,波浪動(dòng)畫最大區(qū)域是該View內(nèi)容區(qū)域的外接圓探孝,但是不會(huì)超過View區(qū)域笋婿。
舉例代碼如下:

/TestDrawable/res/layout/fragment_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="30dp"
        android:background="@drawable/beauty2"
        android:orientation="vertical" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/beauty4"
            android:clickable="true"
            android:layout_marginTop="30dp"
            android:padding="30dp"
            android:src="@drawable/iv_background1" />
    </LinearLayout>

</LinearLayout>

/TestDrawable/res/drawable/iv_background1.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff00ff00" >

</ripple>

運(yùn)行結(jié)果如下:


例二:
在例一的基礎(chǔ)上在ripple根節(jié)點(diǎn)上添加一個(gè)item項(xiàng),相當(dāng)于ripple drawable當(dāng)前擁有一個(gè)Drawable圖層并且當(dāng)將該ripple drawable設(shè)置為View的src屬性值時(shí)該Drawable圖層可以限制波浪動(dòng)畫不會(huì)越過View內(nèi)容區(qū)域顿颅,波浪動(dòng)畫將被繪制在該View內(nèi)容區(qū)域上缸濒,在這種情況下,波浪動(dòng)畫不會(huì)越過View內(nèi)容區(qū)域粱腻,波浪最大區(qū)域是該View內(nèi)容區(qū)域的外接圓庇配,但是波浪動(dòng)畫不會(huì)越過View內(nèi)容區(qū)域。
舉例代碼如下:

/TestDrawable/res/layout/fragment_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="30dp"
        android:background="@drawable/beauty2"
        android:orientation="vertical" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/beauty4"
            android:clickable="true"
            android:layout_marginTop="30dp"
            android:padding="30dp"
            android:src="@drawable/iv_background2" />
    </LinearLayout>

</LinearLayout>

/TestDrawable/res/drawable/iv_background2.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff00ff00" >

    <item android:drawable="@android:color/black"/>

</ripple>

運(yùn)行結(jié)果如下:


例三
在例二中添加的item節(jié)點(diǎn)中添加android:id="@android:id/mask"绍些,相當(dāng)于當(dāng)將該ripple drawable設(shè)置為View的src屬性值時(shí)該item節(jié)點(diǎn)定義的Drawable圖層僅僅是用來限制波浪動(dòng)畫不會(huì)越過View內(nèi)容區(qū)域捞慌。波浪動(dòng)畫將被繪制在該View內(nèi)容區(qū)域上,在這種情況下柬批,波浪動(dòng)畫不會(huì)越過View內(nèi)容區(qū)域啸澡,波浪最大區(qū)域是該View內(nèi)容區(qū)域的外接圓,但是波浪動(dòng)畫不會(huì)超過View內(nèi)容區(qū)域氮帐。
舉例代碼如下:

/TestDrawable/res/layout/fragment_ripple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="30dp"
        android:background="@drawable/beauty2"
        android:orientation="vertical" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="@drawable/beauty4"
            android:clickable="true"
            android:layout_marginTop="30dp"
            android:padding="30dp"
            android:src="@drawable/iv_background3" />
    </LinearLayout>

</LinearLayout>

/TestDrawable/res/drawable/iv_background3.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="#ff00ff00" >

    <item android:id="@android:id/mask"
        android:drawable="@android:color/black"/>

</ripple>

運(yùn)行結(jié)果如下:


5 state list drawable
state list drawable是一個(gè)管理著一個(gè)Drawable對(duì)象集合的StateListDrawable類的對(duì)象嗅虏。集合中的每一個(gè)Drawable對(duì)象對(duì)應(yīng)View的一種狀態(tài),這樣系統(tǒng)會(huì)根據(jù)View的狀態(tài)來選擇合適的Drawable上沐。

FILE LOCATION:
    res/drawable/filename.xml
    The filename is used as the resource ID.
COMPILED RESOURCE DATATYPE:
    Resource pointer to a StateListDrawable.
RESOURCE REFERENCE:
    In Java: R.drawable.filename
    In XML: @[package:]drawable/filename

語法:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize=["true" | "false"]
    android:dither=["true" | "false"]
    android:variablePadding=["true" | "false"] >
    <item
        android:drawable="@[package:]drawable/drawable_resource"
        android:state_pressed=["true" | "false"]
        android:state_focused=["true" | "false"]
        android:state_hovered=["true" | "false"]
        android:state_selected=["true" | "false"]
        android:state_checkable=["true" | "false"]
        android:state_checked=["true" | "false"]
        android:state_enabled=["true" | "false"]
        android:state_activated=["true" | "false"]
        android:state_window_focused=["true" | "false"] />
</selector>

5.1 <selector>節(jié)點(diǎn)元素:
Required 該節(jié)點(diǎn)元素一定被作為根元素皮服。包含一個(gè)或多個(gè)<item>元素。
<selector>節(jié)點(diǎn)元素的常用屬性:

android:constantSize
state list drawable的固有大小是否不隨著View狀態(tài)的改變而改變,因?yàn)閂iew狀態(tài)會(huì)導(dǎo)致
state list drawable切換到具體的Drawable冰更,而不同的Drawable具有不同的固有大小产徊。
true表示state list drawable的固有大小保持不變,這時(shí)state list drawable的固有大小是
內(nèi)部所有Drawable的固有大小的最大值蜀细,false則會(huì)隨著View狀態(tài)的改變而改變舟铜。
此選項(xiàng)的默認(rèn)值是false。

android:dither
是否開啟抖動(dòng)效果奠衔,開啟此選項(xiàng)可以讓圖片在低質(zhì)量的屏幕上仍然獲得較好的顯示效果谆刨。
此選項(xiàng)默認(rèn)值為true。

android:variablePadding
state list drawable的padding表示是否隨著View狀態(tài)的改變而改變归斤,true表示會(huì)隨著View狀態(tài)的改變而改變痊夭,false表示state list drawable的padding是內(nèi)部所有Drawable的padding的最大值。此選項(xiàng)默認(rèn)值為false脏里,并且不建議開啟此選項(xiàng)她我。

5.2 <item>節(jié)點(diǎn)元素:
通過屬性來描述在某個(gè)狀態(tài)下使用某個(gè)drawable。必須是<selector>節(jié)點(diǎn)的子節(jié)點(diǎn)迫横。
<item>節(jié)點(diǎn)元素的常用屬性:

android:drawable:
Drawable resource. Required.引用一個(gè)drawable resource.

android:state_pressed
Boolean. 如果屬性值為true番舆,則使用該state list drawable的組件被按下時(shí)該item被使用;如果屬性值為false矾踱,則使用該state list drawable的組件沒有被按下時(shí)該item被使用恨狈;

android:state_focused
Boolean. 如果屬性值為true,則使用該state list drawable的組件獲取input focus時(shí)該item被使用呛讲;如果屬性值為false禾怠,則使用該state list drawable的組件沒有獲取input focus時(shí)該item被使用;

android:state_selected
Boolean. 如果屬性值為true贝搁,則使用該state list drawable的組件被選擇時(shí)該item被使用吗氏;如果屬性值為false,則使用該state list drawable的組件沒有被選擇時(shí)該item被使用雷逆。例如當(dāng)在幾個(gè)tab間切換時(shí)牲证,被選中的tab和沒有被選中的tab的背景顏色設(shè)置為不同的
github上的PagerSlidingTabStrip應(yīng)該利用到該屬性。

android:state_checkable
Boolean. 如果屬性值為true关面,"true" if this item should be used when the object is checkable; "false" if this item should be used when the object is not checkable. (Only useful if the object can transition between a checkable and non-checkable widget.)

android:state_checked
Boolean. 如果屬性值為true坦袍,則使用該state list drawable的組件被checked時(shí)該item被使用;如果屬性值為false等太,則使用該state list drawable的組件沒有被checked時(shí)該item被使用捂齐。

android:state_activated
Boolean. "true" if this item should be used when the object is activated as the persistent selection (such as to "highlight" the previously selected list item in a persistent navigation view); "false" if it should be used when the object is not activated.
Introduced in API level 11

注意:Android系統(tǒng)會(huì)從上到下進(jìn)行查找,直到查找到第一條匹配的item缩抡,并且如果state list drawable中的某一項(xiàng)沒有設(shè)置狀態(tài)屬性奠宜,則該項(xiàng)會(huì)被應(yīng)用每一次,因此默認(rèn)Item(沒有設(shè)置狀態(tài)屬性)應(yīng)該放到最后一項(xiàng)。

nine patch drawable

9-patch圖像是一種特殊格式的文件压真,因?yàn)锳ndroid知道圖像的哪些部分可以拉伸縮放娩嚼,哪些部分不可以。經(jīng)適當(dāng)處理后滴肿,可保證背景圖的邊角與工具創(chuàng)建的圖像保持一致性岳悟。
為什么要叫做9-patch呢? 9-patch可將圖像分成3× 3的網(wǎng)格泼差,即由 9部分或9 patch組成的網(wǎng)格贵少。網(wǎng)格角落的patch不會(huì)被縮放,邊緣部分的4個(gè)patch只按一個(gè)維度縮放堆缘,而中間部分則同時(shí)按兩個(gè)維度縮放滔灶,如下圖所示:



9-patch圖像和普通的png圖像基本相同,但以下兩點(diǎn)除外: 9-patch圖像文件名是以.9.png結(jié)尾的吼肥,圖像邊緣具有一個(gè)像素寬度的邊框录平,頂部以及左邊框黑線用來標(biāo)記圖像的可伸縮區(qū)域,底部以及右邊框黑線用于標(biāo)記9-patch圖像的可填充內(nèi)容區(qū)域缀皱。 可填充內(nèi)容區(qū)域是內(nèi)容(通常是文字)繪制的地方斗这。若不設(shè)置可填充內(nèi)容區(qū)域,則默認(rèn)與可拉伸區(qū)域保持一致唆鸡。對(duì)應(yīng)NinePatchDrawable類涝影≡娌欤可通過如下兩種方式使用9-path文件争占。
1 直接使用本地的9-path資源文件

file location:
    res/drawable/filename.9.png
    The filename is used as the resource ID.
compiled resource datatype:
    Resource pointer to a NinePatchDrawable.
resource reference:
    In Java: R.drawable.filename
    In XML: @[package:]drawable/filename 

舉例如下:

<Button
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:background="@drawable/myninepatch" />

2 通過xml文件間接使用本地9-path資源文件

file location:
    res/drawable/filename.xml
    The filename is used as the resource ID.
compiled resource datatype:
    Resource pointer to a NinePatchDrawable.
resource reference:
    In Java: R.drawable.filename
    In XML: @[package:]drawable/filename 

語法:

<?xml version="1.0" encoding="utf-8"?>
<nine-patch
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@[package:]drawable/drawable_resource"
    android:dither=["true" | "false"] />

< nine-patch>節(jié)點(diǎn)元素:
< nine-patch>節(jié)點(diǎn)元素的常用屬性:

android:src:
Drawable resource. Required.引用一個(gè)Nine-Patch File

android:dither
當(dāng)位圖不具有與屏幕相同的像素結(jié)構(gòu)時(shí),是否啟用或禁用抖動(dòng)效果(關(guān)于抖動(dòng)效果的說明可以參考預(yù)備知識(shí)部分)序目。

舉例如下:

<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/myninepatch"
    android:dither="false" />

自定義Drawable

Drawable的使用方式很單一臂痕,一種方式用是作View背景的(也是大多數(shù)情況下),另一種方式是作為ImageView的內(nèi)容顯示猿涨。在我的另一篇文章Android自定義View中再講解View的繪制過程中提到過繪制View的第一步就是繪制背景握童,下面看一下View類中繪制背景的源碼:

private void drawBackground(Canvas canvas) {
    final Drawable background = mBackground;
    if (background == null) {
        return;
    }

    setBackgroundBounds();

    // Attempt to use a display list if requested.
    if (canvas.isHardwareAccelerated() && mAttachInfo != null
            && mAttachInfo.mHardwareRenderer != null) {
        mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode);

        final RenderNode renderNode = mBackgroundRenderNode;
        if (renderNode != null && renderNode.isValid()) {
            setBackgroundRenderNodeProperties(renderNode);
            ((DisplayListCanvas) canvas).drawRenderNode(renderNode);
            return;
        }
    }

    final int scrollX = mScrollX;
    final int scrollY = mScrollY;
    if ((scrollX | scrollY) == 0) {
        background.draw(canvas);
    } else {
        canvas.translate(scrollX, scrollY);
        background.draw(canvas);
        canvas.translate(-scrollX, -scrollY);
    }
}

void setBackgroundBounds() {
    if (mBackgroundSizeChanged && mBackground != null) {
        mBackground.setBounds(0, 0,  mRight - mLeft, mBottom - mTop);
        mBackgroundSizeChanged = false;
        rebuildOutline();
    }
}

通過上面的源碼可以很容易的看出View背景的繪制過程:由于Drawable是沒有大小的概念的,所以在繪制背景之前先通過setBackgroundBounds方法設(shè)置Drawable的邊界叛赚,然后調(diào)用Drawable的draw方法繪制背景澡绩。
所以在自定義Drawable時(shí)要實(shí)現(xiàn)Drawable類中的draw方法,下面我實(shí)現(xiàn)了一個(gè)顯示圓形的自定義Drawable(CicleDrawable)俺附,并且CicleDrawable的大小會(huì)隨著View的變化而變化(有上面setBackgroundBounds方法的源碼得知)肥卡。CicleDrawable的實(shí)現(xiàn)代碼如下:

package com.cytmxk.test.drawable.custom;

import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;

/**
 * Created by chenyang on 16/8/13.
 */
public class CicleDrawable extends Drawable {

    private Paint paint;

    public CicleDrawable() {
        this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(0xFF00FF00);
    }

    @Override
    public void draw(Canvas canvas) {
        final Rect r = getBounds();
        canvas.drawCircle(r.exactCenterX(), r.exactCenterY(), Math.min(r.exactCenterX(), r.exactCenterY()), paint);
    }

    @Override
    public void setAlpha(int alpha) {
        paint.setAlpha(alpha);
        invalidateSelf();
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        paint.setColorFilter(colorFilter);
        invalidateSelf();
    }

    @Override
    public int getOpacity() {
        // not sure, so be safe
        return PixelFormat.TRANSLUCENT;
    }
}

上面的代碼我是參考ShapeDrawable類的源碼,所以說源碼是一個(gè)很好的學(xué)習(xí)資料事镣,有些技術(shù)細(xì)節(jié)我們不清楚步鉴,我們就可以查看源碼中類似功能的實(shí)現(xiàn),這樣就會(huì)有針對(duì)性的解決一些問題。

Color State List Resource

Color State List Resource是一個(gè)管理著一個(gè)color集合的ColorStateList對(duì)象氛琢,每一個(gè)color對(duì)應(yīng)著一個(gè)狀態(tài)喊递,因此當(dāng)你將其作為color值供View 對(duì)象使用時(shí),Android系統(tǒng)會(huì)根據(jù)View對(duì)象的當(dāng)前狀態(tài)來選擇合適的color阳似。例如骚勘,一個(gè)按鈕控件可以存在于幾種不同的狀態(tài)(pressed, focused, or niether),使用Color State List Resource可以為這些狀態(tài)提供不同的顏色障般。

file location:
    res/color/filename.xml
    The filename will be used as the resource ID.
compiled resource datatype:
    Resource pointer to a ColorStateList.
resource reference:
    In Java: R.color.filename
    In XML: @[package:]color/filename 

語法:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:color="hex_color"
        android:state_pressed=["true" | "false"]
        android:state_focused=["true" | "false"]
        android:state_selected=["true" | "false"]
        android:state_checkable=["true" | "false"]
        android:state_checked=["true" | "false"]
        android:state_enabled=["true" | "false"]
        android:state_window_focused=["true" | "false"] />
</selector>

1 <selector>節(jié)點(diǎn)元素:
Required 該節(jié)點(diǎn)元素一定被作為根元素调鲸。包含一個(gè)或多個(gè)<item>元素。

2 <item>節(jié)點(diǎn)元素:
通過屬性來描述在某個(gè)狀態(tài)下使用某個(gè)color值挽荡。必須是<selector>節(jié)點(diǎn)的子節(jié)點(diǎn)藐石。
<item>節(jié)點(diǎn)元素的常用屬性:

android:color:
16進(jìn)制的color值. Required. 16進(jìn)制的color值是由一個(gè)RGB值和可選的透明值組成。16進(jìn)制的color值必須以字符'#'開始并且是下面格式的一種:
#RGB
#ARGB
#RRGGBB
#AARRGGBB

android:state_pressed
Boolean. 如果屬性值為true定拟,則使用該Color State List的組件被按下時(shí)該item被使用于微;如果屬性值為false,則使用該Color State List的組件沒有被按下時(shí)該item被使用青自;

android:state_focused
Boolean. 如果屬性值為true株依,則使用該Color State List的組件獲取input focus時(shí)該item被使用;如果屬性值為false延窜,則使用該Color State List的組件沒有獲取input focus時(shí)該item被使用恋腕;

android:state_selected
Boolean. 如果屬性值為true,則使用該Color State List的組件被選擇時(shí)該item被使用逆瑞;如果屬性值為false荠藤,則使用該Color State List的組件沒有被選擇時(shí)該item被使用。例如當(dāng)在幾個(gè)tab間切換時(shí)获高,被選中的tab和沒有被選中的tab的背景顏色設(shè)置為不同的
github上的PagerSlidingTabStrip應(yīng)該利用到該屬性哈肖。

android:state_checkable
Boolean. "true" if this item should be used when the object is checkable; "false" if this item should be used when the object is not checkable. (Only useful if the object can transition between a checkable and non-checkable widget.)

android:state_checked
Boolean. 如果屬性值為true,則使用該Color State List的組件被checked時(shí)該item被使用念秧;如果屬性值為false淤井,則使用該Color State List的組件沒有被checked時(shí)該item被使用。

android:state_activated
Boolean. "true" if this item should be used when the object is activated as the persistent selection (such as to "highlight" the previously selected list item in a persistent navigation view); "false" if it should be used when the object is not activated.
Introduced in API level 11

注意:Android系統(tǒng)會(huì)從上到下進(jìn)行查找摊趾,直到查找到第一條匹配的item币狠,并且如果Color State List Resource中的某一項(xiàng)沒有設(shè)置狀態(tài)屬性,則該項(xiàng)會(huì)被應(yīng)用每一次砾层,因此默認(rèn)Item(沒有設(shè)置狀態(tài)屬性)應(yīng)該放到最后一項(xiàng)漩绵。
舉例如下:

XML file saved at res/color/button_text.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
          android:color="#ffff0000"/> <!-- pressed -->
    <item android:state_focused="true"
          android:color="#ff0000ff"/> <!-- focused -->
    <item android:color="#ff000000"/> <!-- default -->
</selector>
This layout XML will apply the color list to a View:
<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/button_text"
    android:textColor="@color/button_text" />
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市梢为,隨后出現(xiàn)的幾起案子渐行,更是在濱河造成了極大的恐慌轰坊,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祟印,死亡現(xiàn)場(chǎng)離奇詭異肴沫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蕴忆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門颤芬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人套鹅,你說我怎么就攤上這事站蝠。” “怎么了卓鹿?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵菱魔,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我吟孙,道長(zhǎng)澜倦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任杰妓,我火速辦了婚禮藻治,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巷挥。我一直安慰自己桩卵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布倍宾。 她就那樣靜靜地躺著雏节,像睡著了一般。 火紅的嫁衣襯著肌膚如雪凿宾。 梳的紋絲不亂的頭發(fā)上矾屯,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天兼蕊,我揣著相機(jī)與錄音初厚,去河邊找鬼。 笑死孙技,一個(gè)胖子當(dāng)著我的面吹牛产禾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播牵啦,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼亚情,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了哈雏?” 一聲冷哼從身側(cè)響起楞件,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤衫生,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后土浸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體罪针,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年黄伊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泪酱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡还最,死狀恐怖墓阀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拓轻,我是刑警寧澤斯撮,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站扶叉,受9級(jí)特大地震影響吮成,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辜梳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一粱甫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧作瞄,春花似錦茶宵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至契耿,卻和暖如春瞒大,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搪桂。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工透敌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人踢械。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓酗电,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親内列。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撵术,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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