Android Drawable 與 LayerList綜合匯總

先看需求,要求這種效果

vcD4KPHA+yc+0+sLrPC9wPgo8cD48P3htbCB2ZXJzaW9uPQ==”1.0″ encoding=”utf-8″?>

<stroke
android:width=”3dp”
android:color=”@android:color/white” />

<size
android:height=”55dp”
android:width=”55dp” />

<padding
android:bottom=”15dp”
android:left=”15dp”
android:right=”15dp”
android:top=”15dp” />

<stroke
android:width=”3dp”
android:color=”@android:color/white” />

<size
android:height=”40dp”
android:width=”40dp” />

<padding
android:bottom=”15dp”
android:left=”15dp”
android:right=”15dp”
android:top=”15dp” />

<scale
android:ble=”@drawable/repair_iconaa”
android:scaleWidth=”50%”
android:scaleHeight=”50%”
/>

再來重頭從學習drawable^_^

Android把可繪制的對象抽象為Drawable,不同的圖形圖像資源就代表著不同的drawable類型。Android FrameWork提供瞭一些具體的Drawable實現,通常在代碼中都不會直接接觸Drawable的實現類。

在實際的開發過程中,會把使用到的資源都放置在res/drawable目錄,剩下的工作交給Android SDK 就行瞭,當需要使用圖片資源的時候,可以使用@drawable標志在xml中引用drawable資源就行,也可以在代碼中使用id引用這些drawable資源。

在使用drawable資源的時,有一點需要註意,drawable默認是內存共享的,也就說在不同的地方使用瞭同一個drawable,它們都指向相同的資源,而且具有相同的狀態,如果在一個地方修改瞭這個drawable,所有使用它的地方都會改變。

Android內置瞭如下幾種Drawable類型:ColorDrawable、GradientDrawable、BitmapDrawable、 NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、RotateDrawable、AnimationDrawable、LayerDrawable、LevelListDrawable、StateListDrawable、TransitionDrawable。

除瞭這些預置的drawable實現類以外,也可以自定義drawable的實現類型,大部分情況都不需要自定義drawable類型,使用系統提供的這些drawable實現類型已經覆蓋瞭很多情況。在實際的編程過程中也很少會接觸這些具體drawable實現類型,因為編寫android應用程序使用xml可以很容易的創建drawable,隻有在程序中需要修改drawable的屬性時,才需要使用具體的drawable類型提供的方法來處理。下面就來逐個認識這些Drawable類型。

Shape

簡介

作用:XML中定義的幾何形狀

位置:res/drawable/文件的名稱.xml

使用的方法:

Java代碼中:R.drawable.文件的名稱

XML中:Android:background=”@drawable/文件的名稱”

屬性:

Android:shape=[“rectangle” | “oval” | “line” | “ring”]

其中rectagle矩形,oval橢圓,line水平直線,ring環形

中子節點的常用屬性:

漸變

Android:startColor 起始顏色

Android:endColor 結束顏色

Android:angle 漸變角度,0從上到下,90表示從左到右,數值為45的整數倍默認為0;

Android:type 漸變的樣式 liner線性漸變 radial環形漸變 sweep

填充

Android:color 填充的顏色

描邊

Android:width 描邊的寬度

Android:color 描邊的顏色

Android:dashWidth 表示’-‘橫線的寬度

Android:dashGap 表示’-‘橫線之間的距離

圓角

Android:radius 圓角的半徑 值越大角越圓

Android:topRightRadius 右上圓角半徑

Android:bottomLeftRadius 右下圓角角半徑

Android:topLeftRadius 左上圓角半徑

Android:bottomRightRadius 左下圓角半徑

填充

android:bottom=”1.0dip” 底部填充

android:left=”1.0dip” 左邊填充

android:right=”1.0dip” 右邊填充

android:top=”0.0dip” 上面填充

一、ColorDrawable

ColorDrawable 是最簡單的Drawable,它實際上是代表瞭單色可繪制區域,它包裝瞭一種固定的顏色,當ColorDrawable被繪制到畫佈的時候會使用顏色填充Paint,在畫佈上繪制一塊單色的區域。

在xml文件中使用color作為根節點來創建ColorDrawable,它隻有一個android:color屬性,通過它來決定ColorDrawable的顏色,Android並沒有提供修改這個顏色值的Api,所以這個顏色一旦設置之後,就不能直接修改瞭。

下面的xml文件定義瞭一個顏色為紅色的ColorDrawable:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <color xmlns:android="https://schemas.android.com/apk/res/android"
3 android:color="#FF0000" />

當然也可以使用Java代碼創建ColorDrawable,需要註意的是Android中使用一個int類型的數據表示顏色值,通常習慣使用十六進制格式的數據表示顏色值。一個int類型包含四個字節,分別代表顏色的4個組成部分:透明度(Alpha)、紅(RED)、綠(GREEN)、藍(BLUE),每個部分由一個字節(8個bit)表示,取值范圍為0~255。在xml中使用顏色時可以省略透明度(Alpha)部分,如#ff0000表示紅色。但是在代碼中必須要明確指出透明度(Alpha)代表的數據,如果省略瞭就表示完全透明的顏色,例如0xFFFF0000表示紅色,而0xFF0000雖然也表示紅色,但它卻是完全透明的,也就是說當繪制到畫佈上時,看不出有任何效果。

使用Java代碼也可以創建ColorDrawable,代碼如下:

[代碼]java代碼:

view
source

print?

1 ColorDrawable drawable = new ColorDrawable(0xffff0000);

二、GradientDrawable

GradientDrawable 表示一個漸變區域,可以實現線性漸變、發散漸變和平鋪漸變效果,在Android中可以使用GradientDrawable表示很多復雜而又絢麗的界面效果。

可以使用xml定義GradientDrawable,相對於ColorDrawable類型,GradientDrawable要復雜很多,它有很多的元素組成。在xml文件中使用shape作為根節點來創建GradientDrawable,它包含很多屬性和子節點,下面是GradientDrawable的xml文檔節點結構。

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <shape xmlns:android="https://schemas.android.com/apk/res/android">
3 <size /> //定義區域的大小
4 <gradient>//設置區域背景的漸變效果
5 <solid/>//設置區域的背景顏色,如果設置瞭solid會覆蓋gradient的效果
6 <stroke />//設置區域的邊框效果
7 <padding />//設置區域的內邊距
8 </shape>

其中每個節點都有許多屬性需要設置,以達到不同的漸變效果。

以下是幾種不同漸變效果實現的xml文件代碼:

[代碼]xml代碼:

view
source

print?

01
02 <?xml version="1.0" encoding="utf-8"?>
03 <shape
04 xmlns:android="https://schemas.android.com/apk/res/android"
05 android:shape="oval">
06
07 <gradient
08 android:startColor="#ff0000"
09 android:centerColor="#00ff00"
10 android:endColor="#0000ff"
11 android:angle="90" />
12 <stroke
13 android:width="3dip"
14 android:color="#fff"
15 android:dashWidth="4dip"
16 android:dashGap="5dip" />
17 </shape>
18
19
20 <?xml version="1.0" encoding="utf-8"?>
21 <shape xmlns:android="https://schemas.android.com/apk/res/android"
22 android:shape="ring" android:innerRadiusRatio="8"
23 android:thicknessRatio="3" android:useLevel="false">
24 <gradient android:type="sweep" android:useLevel="false"
25 android:startColor="#ff0000" android:endColor="#0000ff" android:centerColor="#00ff00"/>
26 </shape>
27
28
29 <?xml version="1.0" encoding="utf-8"?>
30 <shape xmlns:android="https://schemas.android.com/apk/res/android"
31 android:shape="ring" android:innerRadius="0dip"
32 android:thickness="70dip" android:useLevel="false">
33 <gradient android:type="radial" android:useLevel="false" android:gradientRadius="70"
34 android:startColor="#ff0000" android:endColor="#0000ff" android:centerColor="#00ff00"/>
35 </shape>

以下幾幅圖展示瞭上述三個漸變效果:

圖6-1 線性漸變效果的橢圓

圖6-2 平鋪漸變效果的圓環

圖6-3 發散漸變效果的圓

三、BitmapDrawable

BitmapDrawable 是對bitmap的一種包裝,可以設置它包裝的bitmap在BitmapDrawable區域內的繪制方式,如平鋪填充、拉伸填充或者保持圖片原始大小,也可以在BitmapDrawable區域內部使用gravity指定的對齊方式。

在xml文件中使用bitmap作為根節點來定義BitmapDrawable。

下面的xml代碼定義一個BitmapDrawable,同時設置瞭BitmapDrawable的tileMode 屬性為mirror,通過這樣設置會使用小圖片在水平和豎直方向做鏡面平鋪效果。

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <bitmap xmlns:android="https://schemas.android.com/apk/res/android"
3 android:src="@drawable/png_icon_416"
4 android:tileMode="mirror"
5 android:antialias="true"
6 android:dither="true"
7 >
8 </bitmap>

也可以使用Java代碼實現相同的效果,等價的Java代碼如下:

[代碼]java代碼:

view
source

print?

1 Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.png_icon_416);
2 BitmapDrawable mBitmapDrawable = new BitmapDrawable(mBitmap);
3 mBitmapDrawable.setTileModeXY(TileMode.MIRROR, TileMode.MIRROR);
4 mBitmapDrawable.setAntiAlias(true);
5 mBitmapDrawable.setDither(true);
6 mDrawable = mBitmapDrawable;

效果如下圖所示:

圖6-4 BitmapDrawable運行效果圖

四、NinePatchDrawable

NinePatchDrawable,“點九圖”是Andriod平臺的一種特殊的圖片格式,文件擴展名為:.9.png。支持Android平臺的手機類型很多,有多種不同的分辨率,很多控件的切圖文件在被放大拉伸後,邊角會模糊失真。在android平臺下使用“點九”圖片處理技術,可以將圖片橫向和縱向同時進行拉伸,以實現在多分辨率下的完美顯示效果。點九圖片在拉伸時仍能保留圖像的漸變質感和圓角的精細度。

Android SDK工具集提供瞭處理點九圖片的工具,可以通過draw9patch.bat運行,通過這個工具可以很容易把普通的PNG圖片處理成“點九”圖片。從它的名字也很容易理解“點九”圖的含義,其實相當於把一張PNG圖分成瞭9個部分(九宮格),分別為4個角,4條邊,以及一個中間區域,4個角是不做拉伸的,所以還能一直保持圓角的清晰狀態,而2條水平邊和2條垂直邊分別隻做水平和垂直拉伸,所以不會出現邊框被拉粗的情況,隻有中間用黑線指定的區域做拉伸,通過這種處理方式圖片才不會失真。如圖6-5所示,對4條黑線分別做瞭註釋。左邊和上邊的黑線形成的矩形區域是圖片的拉伸區域,下邊和右邊形成的矩形區域是內容所在的區域。黑線可以是連續的也可以是不連續的,不過為瞭達到最好的顯示效果,最好使用連續的黑線。

圖6-5 點九圖片示意圖

使用瞭*.9.png圖片技術後,隻需要采用一套界面切圖去適配不同的分辨率,而且大幅減少安裝包的大小。Android FrameWork在顯示點九圖片時使用瞭高效的優化算法,所示應用程序不需要專門做處理就可以實現圖片拉伸自適應,減少瞭代碼量和實際開發的工作量。

在xml文件中使用使用nine-patch作為根節點創建NinePatchDrawable。同時,也可以使用bitmap包裝點九圖片,android FrameWork會根據android:src屬性設置的圖片類型來生成對應的drawable。代碼如下:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <nine-patch
3 xmlns:android="https://schemas.android.com/apk/res/android"
4 android:src="@drawable/droid_logo"
5 android:dither="true" />

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <bitamp
3 xmlns:android="https://schemas.android.com/apk/res/android"
4 android:src="@drawable/droid_logo"
5 android:dither="true" />

下面看一下原始點九圖片以及拉伸之後的效果:

圖6-6 原始點九圖片

圖6-7 點九圖片拉伸之後的效果

最後,需要指出的是,Android雖然可以使用Java代碼創建NinePatchDrawable,但是極少情況會那麼做,主要的原因是由於Android SDK會在編譯工程時對點九圖片進行編譯,形成特殊格式的圖片。使用代碼創建NinePatchDrawable時隻能針對編譯過的點九圖片資源,對於沒有編譯過的點九圖片資源都當做BitmapDrawable對待。在使用點九圖片時需要註意的是,點九圖隻能適用於拉伸的情況,對於壓縮的情況並不適用,如果需要適配很多分辨率的屏幕時需要把點九圖做的小一點。

五、InsetDrawable

InsetDrawable 表示一個drawable嵌入到另外一個drawable內部,並且在內部留一些間距,這一點很像drawable的padding屬性,區別在於 padding表示drawable的內容與drawable本身的邊距,insetDrawable表示兩個drawable和容器之間的邊距。當控件需要的背景比實際的邊框小的時候比較適合使用InsetDrawable。

在xml文件中使用inset作為跟節點定義InsetDrawable。

下面的xml定義瞭一個四邊邊距都為20dip的InsetDrawable,代碼如下:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <inset xmlns:android="https://schemas.android.com/apk/res/android"
3 android:drawable="@drawable/bitmap_bell"
4 android:insetLeft="20dp"
5 android:insetRight="20dp"
6 android:insetTop="20dp"
7 android:insetBottom="20dp"
8 >
9 </inset>

效果如下圖所示:

圖6-8 InsetDrawable運行效果圖

六、ClipDrawable

ClipDrawable 是對一個Drawable進行剪切操作,可以控制這個drawable的剪切區域,以及相相對於容器的對齊方式,android中的進度條就是使用一個ClipDrawable實現效果的,它根據level的屬性值,決定剪切區域的大小。

在xml文件中使用clip作為根節點定義ClipDrawable。

需要註意的是ClipDrawable是根據level的大小控制圖片剪切操作的,官方文檔的note中提到:The drawable is clipped completely and not visible when the level is 0 and fully revealed when the level is 10,000。也就是level的大小從0到10000,level為0時完全不顯示,為10000時完全顯示。是用Drawable提供的setLevel(int level)方法來設置剪切區域。

下面為定義ClipDrawable的代碼:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <clip xmlns:android="https://schemas.android.com/apk/res/android"
3 android:clipOrientation="horizontal"
4 android:drawable="@drawable/bitmap_android"
5 android:gravity="left"
6 >
7 </clip>

如果沒有android:drawable屬性,必須要設置一個任意類型的drawable作為子節點,代碼如下:

[代碼]xml代碼:

view
source

print?

01 <?xml version="1.0" encoding="utf-8"?>
02 <clip xmlns:android="https://schemas.android.com/apk/res/android"
03 android:clipOrientation="horizontal"
04 android:gravity="left"
05 >
06 <bitmap
07 android:src="@drawable/android_text"
08 android:gravity="center"
09 />
10 </clip>

效果如下圖所示:

七、ScaleDrawable

ScaleDrawable是對一個Drawable進行縮放操作,可以根據level屬性控制這個drawable的縮放比率,也可以設置它在容器中的對齊方式。

在xml文件中使用scale作為根節點來創建RotateDrawable。

創建ScaleDrawable的代碼如下:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2
3 <scale xmlns:android="https://schemas.android.com/apk/res/android"
4 android:drawable="@drawable/smiley_smile"
5 android:scaleWidth="100%"
6 android:scaleHeight="100%"
7 >
8
9 </scale>

效果如下圖所示:

圖6-10 ScaleDrawable運行效果圖

八、RotateDrawable

RotateDrawable 是對一個Drawable進行旋轉操作,可以根據level屬性控制這個drawable旋轉角度,也可以設置相對於它所在容器的對齊方式。

在xml文件中使用rotate作為根節點來定義RotateDrawable.

創建RotateDrawable的代碼如下:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <rotate xmlns:android="https://schemas.android.com/apk/res/android"
3 android:drawable="@drawable/smiley_smile"
4 android:pivotX="50%"
5 android:pivotY="50%"
6 >
7
8
9 </rotate>

效果如下圖所示:

圖6-11 RotateDrawable運行效果圖

九、AnimationDrawable

AnimationDrawable 對應於Android中的幀動畫,就是把一系列的drawable按照一定的順序,一幀一幀的播放,並且可以使用android:oneshot屬性設置是否循環播放。

在xml文件中使用animation-list作為根節點定義AnimationDrawable,使用item設置需要播放的每一幀使用的drawable資源,以及每一幀持續的時常。

下面的代碼定義瞭一個包含五幀的AnimationDrawable,幀間隔為300毫秒,代碼如下:

[代碼]xml代碼:

view
source

print?

01 <?xml version="1.0" encoding="utf-8"?>
02 <animation-list xmlns:android="https://schemas.android.com/apk/res/android"
03 android:oneshot="false">
04 <item
05 android:drawable="@drawable/level1"
06 android:duration="300"
07 />
08 <item
09 android:drawable="@drawable/level2"
10 android:duration="300"
11 />
12 <item
13 android:drawable="@drawable/level3"
14 android:duration="300"
15 />
16 <item
17 android:drawable="@drawable/level4"
18 android:duration="300"
19 />
20 <item
21 android:drawable="@drawable/level5"
22 android:duration="300"
23 />
24 </animation-list>

定義瞭AnimationDrawable之後需要主動調用AnimationDrawable的start播放動畫,需要註意的是,當我們在Activity的oncreate方法中調用start方法時會沒有任何效果,那是因

為view還沒有初始化完成,無法播放動畫,所以需要使用handler來延遲播放動畫,具體實現代碼如下:

[代碼]java代碼:

view
source

print?

1 mHandler.postDelayed(new Runnable() {
2
3 @Override
4 public void run() {
5 // TODO Auto-generated method stub
6 ((AnimationDrawable)mDrawable).start();
7
8 }
9 }, 1000);

十、LayerDrawable

LayerDrawable 管理一組drawable,每個drawable都處於不同的層,當它們被繪制的時候,按照順序全部都繪制到畫佈上。雖然這些drawable會有交差或者重疊的區域,但是它們是位於不同的層,彼此之間不會影響。

在xml文件中使用layer-list作為根節點來定義LayerDrawable,通過item子節點定義每一層的drawable,layer-list沒有屬性節點,隻包含item子節點。

下面的xml定義瞭一個包含三層的LayerDrawable,為瞭清楚的看到它們分別位於不同的層,可以給每一層都設置瞭一些透明度,代碼如下:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <layer-list xmlns:android="https://schemas.android.com/apk/res/android" >
3 <item android:drawable="@drawable/layer1" />
4 <item android:drawable="@drawable/layer2" />
5 <item android:drawable="@drawable/layer3" />
6 </layer-list>

效果如下圖所示:

圖6-12 LayerDrawable運行效果圖

十一、LevelListDrawable

管理一組drawable,每一個drawable都對應一個level范圍,當它們被繪制的時候,根據level屬性值選取對應的一個drawable繪制到畫佈上。

在xml文件中使用level-list作為根節點來定義LevelListDrawable,通過item子節點定義每一層的drawable,level-list沒有屬性節點,隻包含item子節點。

創建LevelListDrawable的代碼如下:

[代碼]xml代碼:

view
source

print?

01 <?xml version="1.0" encoding="utf-8"?>
02 <level-list xmlns:android="https://schemas.android.com/apk/res/android" >
03
04 <item
05 android:maxLevel="2000"
06 android:drawable="@drawable/level1" />
07 <item
08 android:maxLevel="4000"
09 android:drawable="@drawable/level2" />
10 <item
11 android:maxLevel="6000"
12 android:drawable="@drawable/level3" />
13 <item
14 android:maxLevel="8000"
15 android:drawable="@drawable/level4" />
16 <item
17 android:maxLevel="10000"
18 android:drawable="@drawable/level5" />
19
20 </level-list>

效果如下圖所示:

圖6-13 LevelListDrawable運行效果圖1

圖6-14 LevelListDrawable運行效果圖2

十二、StateListDrawable

StateListDrawable管理一組drawable,每一個drawable都對應著一組狀態,狀態的選擇類似於java中的switch-case組合,按照順序比較狀態,當遇到匹配的狀態後,就返回對應的drawable,因此需要把最精確的匹配放置在最前面,按照從精確到粗略的順序排列。

StateListDrawable在Android中使用的非常廣泛,所有控件的背景基本上都使用瞭StateListDrawable,比如按鈕就具有很多狀態,按下狀態、選中狀態、默認狀態、禁用狀態等等,像這樣在不用的狀態下顯示效果不一樣的時候,就是需要使用StateListDrawable的時候。

在xml文件中使用selector作為根節點來定義StateListDrawable,並使用item定義不同狀態下的drawable。

創建StateListDraw的代碼如下:

[代碼]xml代碼:

view
source

print?

01 <?xml version="1.0" encoding="utf-8"?>
02 <selector xmlns:android="https://schemas.android.com/apk/res/android" >
03 <item android:state_focused="false"
04 android:state_pressed="false"
05 android:drawable="@drawable/gradient_normal"
06 />
07
08 <item android:state_pressed="true"
09 android:drawable="@drawable/gradient_pressed"
10 />
11
12 <item android:state_focused="true"
13 android:drawable="@drawable/gradient_focused"
14 />
15
16 </selector>

效果如下圖所示:

圖6-15 Normal狀態下StateListDrawable運行效果圖

圖6-16 Focused狀態下StateListDrawable運行效果圖

圖6-17 Pressed狀態下StateListDrawable運行效果圖

十三、TransitionDrawable

TransitionDrawable 是LayerDrawable的子類,不過它隻負責管理兩層drawable,並且提供瞭一個透明度變化的動畫,可以控制從一層drawable過度到另外一層drawable的動畫效果。

在xml文件中使用transition作為根節點來定義TransitionDrawable,通過item子節點定義兩層使用的drawable。

創建TransitionDrawable的代碼如下:

[代碼]xml代碼:

view
source

print?

1 <?xml version="1.0" encoding="utf-8"?>
2 <transition xmlns:android="https://schemas.android.com/apk/res/android" >
3 <item android:drawable="@drawable/smiley_smile"/>
4 <item android:drawable="@drawable/smiley_smile_glasses"/>
5
6 </transition>

在使用AnimationDrawable的時,需要主動調用startTransition方法啟動兩個層之間的切換動畫,也可以調用reverseTransition方法啟動逆向切換動畫,它們都可以接受一個毫秒數,作為動畫的持續時間。代碼如下:

[代碼]java代碼:

view
source

print?

1 mHandler.postDelayed(new Runnable() {
2
3 @Override
4 public void run() {
5 // TODO Auto-generated method stub
6 ((TransitionDrawable)mDrawable).startTransition(2000);
7 }
8 }, 1000);

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *