1. 程式人生 > >Android樣式的開發之drawable

Android樣式的開發之drawable

0 概述

res/drawable目錄下是Android用來存放圖片資原始檔的路徑。這裡除了有常規的圖片外,還支援selector/shape等定製或自定義圖片。

資源命名規則

下面將詳細分析:

1.1 StateListDrawable

1.2 GradientDrawable

1.3 ShapeDrawable

2 BitmapDrawable

對應的xml標籤為bitmap。

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

android:src 必填項,指定圖片資源,只能是圖片,不能是xml定義的drawable資源

android:gravity 設定圖片的對齊方式
    比如在layer-list中,預設會盡量填滿整個檢視,導致圖片可能會被拉伸,
    為了避免被拉伸,就可以設定對齊方式,可取值為下面的值,多個取值可以用 | 分隔:

    top 圖片放於容器頂部,不改變圖片大小    
    bottom 圖片放於容器底部,不改變圖片大小
    left 圖片放於容器左邊,不改變圖片大小
    right 圖片放於容器右邊,不改變圖片大小
    center 圖片放於容器中心位置,包括水平和垂直方向,不改變圖片大小
    fill 拉伸整張圖片以填滿容器的整個高度和寬度,預設值
    center_vertical 圖片放於容器垂直方向的中心位置,不改變圖片大小
    center_horizontal 圖片放於容器水平方向的中心位置,不改變圖片大小
    fill_vertical 在垂直方向上拉伸圖片以填滿容器的整個高度
    fill_horizontal 在水平方向上拉伸圖片以填滿容器的整個寬度
    clip_vertical 附加選項,裁剪基於垂直方向的gravity設定
        設定top時會裁剪底部,設定bottom時會裁剪頂部,其他情況會同時裁剪頂部和底部
    clip_horizontal 附加選項,裁剪基於水平方向的gravity設定
        設定left時會裁剪右側,設定right時會裁剪左側,其他情況會同時裁剪左右兩側

android:
antialias 設定是否開啟抗鋸齒 android:dither 設定是否抖動,圖片與螢幕的畫素配置不同時會用到。 當每個顏色值以低於8位表示時,對應影象做抖動處理可以實現在可顯示顏色總數比較低時 還保持較好的顯示效果。比如圖片是ARGB 8888的,而螢幕是RGB565 android:filter 設定是否允許對圖片進行濾波 對圖片進行收縮或者延展使用濾波可以獲得平滑的外觀效果 android:tint 給圖片著色,設定的是顏色值.注意:使用android:tint指定顏色時一定要帶透明度。 比如圖片本來是黑色的,著色後可以變成白色 android:
tintMode 著色模式,也是API 21才新增的屬性 src_in 取兩層繪製交集,顯示上層 src_over 正常繪製顯示,上下層繪製重疊 src_atop 取下層非交集部分與上層交集部分。 multiply 取兩層繪製交集 screen 上下層都顯示 add 混合遮罩,drawable顏色和透明度 tintMode對應的Java設定 PorterDuff.Mode.CLEAR 所繪製不會提交到畫布上。 PorterDuff.Mode.SRC 顯示上層繪製圖片 PorterDuff.Mode.DST 顯示下層繪製圖片 PorterDuff.Mode.SRC_OVER 正常繪製顯示,上下層繪製疊蓋。 PorterDuff.Mode.DST_OVER 上下層都顯示。下層居上顯示。 PorterDuff.Mode.SRC_IN 取兩層繪製交集。顯示上層。 PorterDuff.Mode.DST_IN 取兩層繪製交集。顯示下層。 PorterDuff.Mode.SRC_OUT 取上層繪製非交集部分。 PorterDuff.Mode.DST_OUT 取下層繪製非交集部分。 PorterDuff.Mode.SRC_ATOP 取下層非交集部分與上層交集部分 PorterDuff.Mode.DST_ATOP 取上層非交集部分與下層交集部分 PorterDuff.Mode.XOR 取兩層繪製非交集。兩層繪製非交集。 PorterDuff.Mode.DARKEN 上下層都顯示。變暗 PorterDuff.Mode.LIGHTEN 上下層都顯示。變亮 PorterDuff.Mode.MULTIPLY 取兩層繪製交集 PorterDuff.Mode.SCREEN 上下層都顯示。

這裡寫圖片描述

android:tileMode 設定圖片平鋪的方式,tile啟用時,gravity將被忽略。tile取值如下:
    disable 不做任何平鋪,預設設定
    repeat 圖片重複鋪滿
    mirror 使用交替映象的方式重複圖片的繪製
    clamp 複製圖片邊緣的顏色來填充容器剩下的空白部分,
        比如引入的圖片如果是白色邊緣,那麼圖片所在的容器裡除了圖片,剩下的空間都會被填充成白色

android:alpha 設定圖片的透明度
    xml中:取值範圍為0-1之間,0為全透明,1為全不透明,API 11+才支援
    Java中:取值範圍為0-255之間,0為全透明,255為全不透明,API 11+才支援

android:mipMap 設定是否可以使用mipmap,但API 17+

android:autoMirrored 設定圖片是否需要映象反轉,
    當佈局方向是RTL,即從右到左佈局時才有用,API 19才新增的屬性

android:tileModeXtileMode一樣設定圖片的平鋪方式
    這個屬性只設置水平方向的平鋪方式,這是API 21才新增的屬性

android:tileModeYtileMode一樣設定圖片的平鋪方式
    這個屬性只設置垂直方向的平鋪方式,這是API 21才新增的屬性

注:這裡需要將BitmapDrawable設定為背景,而不是imageview的src,否則可能無效。

兩種實現方式示例:
xml:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:antialias="true"
    android:dither="true"
    android:src="@mipmap/ic_launcher"
    android:tileMode="mirror">
</bitmap>

java:

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), bitmap);
        bitmapDrawable.setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
        bitmapDrawable.setAntiAlias(true);
        bitmapDrawable.setDither(true);

3 NinePatchDrawable

3.1 點9圖片

點九圖片副檔名為:.9.png,通過點九圖片可以控制拉伸區域,做區域性拉伸。

畫點九圖一般用Android SDK工具集裡的draw9patch工具,只需要在四條邊畫黑線就可以了
這裡寫圖片描述

拉伸區域就是圖片會被拉伸的部分,可以為1個點,也可以為一條線,甚至也可以為斷開的幾個點或幾條線,總之,有黑點的地方就會被拉伸,沒有黑點的地方就不會被拉伸。

顯示內容區域其實就等於預設給使用的控制元件設定了padding,控制元件的內容只能顯示在內容區域內。
點9圖片一般只適用於拉伸情況,不適用與壓縮情況,故需要把圖片做小,以適配小螢幕。

一般很少使用Java程式碼NinePatchDrawable建立點9圖片,因為Android編譯的時候會對點9進行特殊處理。

3.2 nine-patch標籤

nine-patch標籤可以對點九圖片做一些設定處理:

android:src 必填項,必須指定點九型別的圖片
android:dither 設定是否抖動,圖片與螢幕的畫素配置不同時會用到
android:tint 給圖片著色
android:tintMode 著色模式,
android:alpha 設定圖片的透明度
android:autoMirrored 設定圖片是否需要映象反轉

以上屬性同bitmap屬性一致,當然.9圖片也是可以直接使用bitmap標籤的。這裡需要注意的是src只能使用drawable中的資源,不能使用mipmap中資源示例:

<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/catt"
    android:alpha="0.3"
    >
</nine-patch>

4 InsetDrawable

InsetDrawable表示將一個Drawable嵌入到另一個Drawable中,且在內部保留一些間距。其用法和View的padding類似,只不過padding是設定Drawable內容與Drawable邊界的距離,而InsetDrawable表示兩個drawable與View容器之間的邊界距離。其對於的xml檔案標示為insert。

當控制元件需要的背景比實際的邊框小的時候適合使用InsertDrawable。

android:drawable 指定drawable資源,如果不設定該屬性,也可以定義drawable型別的子標籤
android:visible 設定初始的可見性狀態,預設為false
android:insetLeft 左邊距
android:insetRight 右邊距
android:insetTop 頂部邊距
android:insetBottom 底部邊距
android:inset 設定統一邊距,會覆蓋上面四個屬性,但API 21+

使用示例,首先是定義:

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@mipmap/cat"
    android:visible="true"
    android:inset="100dp">

</inset>

然後是在xml中引用方式,設定到background或者src中。

android:src="@drawable/drawable_insert"

android:background="@drawable/drawable_insert"

5 ClipDrawable

ClipDrawable可以對drawable進行裁剪,可以控制這個Drawable的裁剪區域,以及相對於容器的對其方式。通過設定level值控制裁剪多少,level取值範圍為0~10000,預設為0,表示完全裁剪,圖片將不可見;10000則完全不裁剪,可見完整圖片.例如在做進度條時很有用。
ClipDrawable的xml定義為clip

clip屬性說明:

android:drawable 指定drawable資源,如果不設定該屬性,也可以定義drawable型別的子標籤

android:clipOrientation 設定裁剪的方向,取值為以下兩個值之一:
    horizontal 在水平方向上進行裁剪,條狀的進度條就是水平方向的裁剪
    vertical 在垂直方向上進行裁剪

android:gravity 設定裁剪的位置,可取值如下,多個取值用 | 分隔:
    top 圖片放於容器頂部,不改變圖片大小。當裁剪方向為vertical時,會裁掉圖片底部
    bottom 圖片放於容器底部,不改變圖片大小。當裁剪方向為vertical時,會裁掉圖片頂部
    left 圖片放於容器左邊,不改變圖片大小,預設值。當裁剪方向為horizontal,會裁掉圖片右邊部分
    right 圖片放於容器右邊,不改變圖片大小。當裁剪方向為horizontal,會裁掉圖片左邊部分
    center 圖片放於容器中心位置,包括水平和垂直方向,不改變圖片大小。
        當裁剪方向為horizontal時,會裁掉圖片左右部分;
        當裁剪方向為vertical時,會裁掉圖片上下部分
    fill 拉伸整張圖片以填滿容器的整個高度和寬度。
        這時候圖片不會被裁剪,除非level設為了0,此時圖片不可見
    center_vertical 圖片放於容器垂直方向的中心位置,不改變圖片大小。裁剪和center時一樣
    center_horizontal 圖片放於容器水平方向的中心位置,不改變圖片大小。裁剪和center時一樣
    fill_vertical 在垂直方向上拉伸圖片以填滿容器的整個高度。
        當裁剪方向為vertical時,圖片不會被裁剪,除非level設為了0,此時圖片不可見
    fill_horizontal 在水平方向上拉伸圖片以填滿容器的整個寬度。
        當裁剪方向為horizontal時,圖片不會被裁剪,除非level設為了0,此時圖片不可見
    clip_vertical 附加選項,裁剪基於垂直方向的gravity設定
        設定top時會裁剪底部,設定bottom時會裁剪頂部,其他情況會同時裁剪頂部和底部
    clip_horizontal 附加選項,裁剪基於水平方向的gravity設定
        設定left時會裁剪右側,設定right時會裁剪左側,其他情況會同時裁剪左右兩側

使用示例,首先是定義:

<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:gravity="top">
    <bitmap
        android:gravity="center"
        android:src="@mipmap/girl5" />

</clip>

xml中引用方法同上,最後是在Java中定義level,level取值範圍為0~10000,預設為0,表示完全裁剪,圖片將不可見;10000則完全不裁剪.

imageView = (ImageView) findViewById(R.id.clip_drawable);
ClipDrawable clipDrawable = (ClipDrawable) imageView.getDrawable();
clipDrawable.setLevel(800);

6 ScaleDrawable

ScaleDrawable是一個對Drawable進行縮放操作的控制元件,其在xml中使用scale標籤,和clip一樣是通過設定level來控制縮放的比例。

android:drawable 指定drawable資源,如果不設定該屬性,也可以定義drawable型別的子標籤

android:scaleHeight 設定可縮放的高度,用百分比表示,格式為XX%,
    0%表示不做任何縮放,50%表示只能縮放一半

android:scaleWidth 設定可縮放的寬度,用百分比表示,格式為XX%,
    0%表示不做任何縮放,50%表示只能縮放一半

android:scaleGravity 設定drawable縮放後的位置,取值和bitmap標籤的一樣,預設值是left

android:useIntrinsicSizeAsMinimum 設定drawable原有尺寸作為最小尺寸,
    設為true時,縮放基本無效,API 11+

7 LayerDrawable

LayerDrawable管理一組drawable,每個drawable處於不同的層,繪製的時候按照順序全部繪製到畫布上,可能會由重疊,但是處於不同層的Drawable不會互相影響。

在xml檔案中使用layer-list作為根節點來定義LayerDrawable,通過子節點item來定義每一層的Drawable,layer-list沒有屬性節點。

item 中可以指定drawable,引數

bottom  下邊距
top     上邊距
left    左邊距
right   右邊距
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:bottom="100dp">
        <bitmap
            android:alpha="0.3"
            android:src="@mipmap/girl1" />
    </item>
    <item android:top="100dp">
        <bitmap
            android:alpha="0.3"
            android:src="@mipmap/girl2" />
    </item>
</layer-list>

8 LevelListDrawable

LevelListDrawable管理一組drawable,每個drawable對應一個level範圍,當它們被繪製的時候,根據level屬性值選取對應的drawable繪製到畫布。
在xml中由level-list實現,level-list通過新增item子標籤來新增相應的drawable。

當需要在一個View中顯示不同圖片的時候,level-list就可以派上用場了。例如Android的電量顯示就是使用的此控制元件。

android:drawable 指定drawable資源,如果不設定該屬性,也可以定義drawable型別的子標籤
android:minLevelitem的最小levelandroid:maxLevelitem的最大level

9 RotateDrawable

使用RotateDrawable可以對一個drawable進行旋轉操作.可以使用level屬性控制旋轉的角度。
在xml中使用rotate結點來定義RotateDrawable。

android:drawable 指定drawable資源,如果不設定該屬性,也可以定義drawable型別的子標籤

android:fromDegrees 起始的角度度數

android:toDegrees 結束的角度度數,正數表示順時針,負數表示逆時針

android:pivotX 旋轉中心的X座標,浮點數或是百分比。
    浮點數表示相對於drawable的左邊緣距離單位為px,如5; 
    百分比表示相對於drawable的左邊緣距離按百分比計算,如5%; 
    另一種百分比表示相對於父容器的左邊緣,如5%p; 
    一般設定為50%表示在drawable中心

android:pivotY 旋轉中心的Y座標,同上。

android:visible 設定初始的可見性狀態,預設為false

要讓它可以旋轉,還需要設定level值。level取值範圍為0~10000,應用到rotate,則與fromDegrees~toDegrees相對應,如上面例子的角度範圍為0~180,那麼,level取值0時,則旋轉為0度;level為10000時,則旋轉180度;level為5000時,則旋轉90度。因為level預設值為0,所以圖片沒有轉變。那麼,我們想轉180度,其實可以將fromDegrees設為180,而不設定toDegrees,這樣,不用再在程式碼裡設定level圖片就可以旋轉180了

10 TransitionDrawable

TransitionDrawable是LayerDrawable的子類,它只負責兩層的drawable,並且提供了一個透明度變化的動畫,用來控制從一層drawable過渡到另一層drawable的動畫效果。預設的過渡動畫為淡入淡出效果。

xml中使用transition標籤生成TransitionDrawable,要切換時,需要主動呼叫

item引數說明:

id:資源ID,可以通過findViewById找到以及修改此資源
top:    與頂部距離
bottom:與下邊距離
right:  與右邊距離
left:與左邊距離
start:  效果同left
end:    效果同right

TransitionDrawable的startTransition()方法,引數為動畫的毫秒數,也可以呼叫reverseTransition()方法逆向切換。另外,如果在Activity的onCreate()方法裡直接呼叫start()方法會沒有效果,因為view還沒有初始化完成是播放不了動畫的。一般使用handler的post方法延遲處理

11 AnimationDrawable

AnimationDrawable對應於Android幀動畫,就是把一系列的Drawable按照一定的順序,一幀一幀的播放。對應的xml根結點為animation-list標籤。

animation-list通過新增item子標籤設定每一幀使用的drawable資源,以及每一幀持續的時間。

android:oneshot屬性設定是否迴圈播放,設為true時,只播放一輪就結束,設為false時,則會輪詢播放。

android:duration屬性設定該幀持續的時間,以毫秒數為單位。

animation-list對應的Drawable類為AnimationDrawable,要讓動畫執行起來,需要主動呼叫
AnimationDrawable的start()方法。另外,如果在Activity的onCreate()方法裡直接呼叫start()方法會沒有效果,因為view還沒有初始化完成是播放不了動畫的。一般使用handler的post方法延遲處理

12 animated-rotate

rotate標籤只是將原有的drawable轉個角度變成另一個drawable,它是靜態的。而animated-rotate則會讓drawable不停地做旋轉動畫。

android:drawable 指定drawable資源,如果不設定該屬性,也可以定義drawable型別的子標籤
android:pivotX 旋轉中心的X座標
android:pivotY 旋轉中心的Y座標
android:visible 設定初始的可見性狀態,預設為false

14 animated-selector

api21+才支援。它是基於狀態的,根據view的選中與啟用等狀態,使用相應的transition來過渡到正確的狀態。裡面包含兩種標籤 item和transition

13 VectorDrawable

VectorDrawable向量圖,無論放大縮小都不回失真。支援API21+.Android官方提供了一個VectorDrawableCompat以支援低版本的庫。

VectorDrawable對應的xml檔案為vector。

vector屬性說明

height  向量圖絕對高度,必填(Used to define the intrinsic width of the drawable.)
weight 向量圖絕對寬度,必填(Used to define the intrinsic height the drawable)
ViewportWidth 畫布canvas寬度 (Used to define the width of the viewport space.
     Viewport is basically the virtual canvas where the paths are drawn on.)
viewportHeight  畫布canvas高度(Used to define the height of the viewport space.)
    以上兩個屬性必填,定義的Path路徑必須在這個畫布大小裡去繪製,超出畫布就顯示不出來。
tint    著色
tintMode 著色模式
autoMirrored  RTL時使用,是否映象。
alpha 透明度   

vector可以包含group/path/clip-path三個子標籤.使用android:name屬性給每個group和path指定一個唯一的名字,這樣你可以從動畫的定義中找到他們

group元素定義一系列路徑或者子組,可以給一組path定義動畫。

path元素定義可繪圖的路徑

android:fillColor屬性定義繪製顏色
android:pathData定義繪製路徑。

pathData中支援的path指令

M = moveto(M X,Y) :將畫筆移動到指定的座標位置
L = lineto(L X,Y) :從當前點畫直線到指定的座標位置
H = horizontal lineto(H X):從當前點畫水平線到指定的X座標位置,H為垂直點
V = vertical lineto(V Y):從當前點畫垂直線到指定的Y座標位置,V為垂直點
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次貝賽曲線
S = smooth curveto(S X2,Y2,ENDX,ENDY)
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次貝賽曲線
T = smooth quadratic Belzier curveto(T ENDX,ENDY):對映
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧線
    RX,RY指所在橢圓的半軸大小
    XROTATION指橢圓的X軸與水平方向順時針方向夾角。
    FLAG1只有兩個值,1表示大角度弧線,0為小角度弧線。
    FLAG2只有兩個值,確定從起點至終點的方向,1為順時針,0為逆時針
    X,Y為終點座標
Z = closepath():關閉路徑

pathData中的path指令使用原則

①座標軸為以(0,0)為中心,X軸水平向右,Y軸水平向下。
②所有指令大小寫均可。大寫絕對定位,參照全域性座標系;小寫相對定位,參照父容器座標系
③指令和資料間的空格可以省略
④同一指令出現多次可以只用一個

注意,'M'處理時,只是移動了畫筆, 沒有畫任何東西。 它也可以在後面給出上同時繪製不連續線。

使用path屬性來設定向量圖,一般使用工具(比如Expression Design)來製作,再匯出為XAML Silverlight畫布格式的內容,賦值給path屬性的pathData就可以繪製出該向量圖。向量圖可以參考

clip-path Defines path to be the current clip.

14 AnimatedVectorDrawable

子類AnimatedVectorDrawable可以讓VectorDrawable動起來:通過改變VectorDrawable的屬性來讓其呈現動畫效果,實際是實現了屬性動畫。其xml實現為animated-vector

實現AnimatedVectorDrawable步驟:

drawable使用xml中實現vector
drawable使用xml中實現animated-vector
animator中實現一個或多個objectAnimator

AnimatedVectorDrawable屬性

drawable 指定向量圖

AnimatedVectorDrawable子標籤

target 根據name找到相應的group name等於name的group,執行animation定義的動畫效果(可以是animator動畫)。

Animated vector drawable可以讓和元素的屬性動態變化。定義一組path或者子group,而元素定義需要繪製的路徑。當你想讓VectorDrawable呈現動畫效果,在定義VectorDrawable的時候需要為group和path的android:name屬性設定一個唯一的名字,以便在Animated vector drawable中找到它們

15 RippleDrawable

RippleDrawable,水波紋效果。對應的xml中為ripple。

16 原始碼地址