概述
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)系如下圖所示:
下面我會(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)技術(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" />