Android有很多種drawable類型,除了前幾篇詳細講解的shape、selector、layer-list,還有上一篇提到的color、bitmap、clip、scale、inset、transition、rotate、animated-rotate、lever-list等等,本篇文章將彙總介紹所有剩下的drawable資源。
普通圖片
圖片是最常用的drawable資源,格式包括:png(推薦)、jpg(可接受)、gif(不建議)。用圖片資源需要根據不同屏幕密度提供多張不同尺寸的圖片,它們的關係如下表:
密度分類 | 密度值範圍 | 代表分辨率 | 圖標尺寸 | 圖片比例 |
---|---|---|---|---|
mdpi | 120~160dpi | 320x480px | 48x48px | 1 |
hdpi | 160~240dpi | 480x800px | 72x72px | 1.5 |
xhdpi | 240~320dpi | 720x1280px | 96x96px | 2 |
xxhdpi | 320~480dpi | 1080x1920px | 144x144px | 3 |
xxxhdpi | 480~640dpi | 1440x2560px | 192x192px | 4 |
本來還有一個ldpi的,但現在這種小屏幕的設備基本滅絕了,所以不需要再考慮適配。如上表所示,一套圖片一般需要提供5張不同比例的圖片。還好有切圖工具,可以讓切圖變得簡單,這裏推薦兩款:Cutterman和Cut&Slice me,都是Photoshop下的插件,輸出支持android、ios和web三種平臺。
使用切圖工具雖然方便了,但還是無法避免一套圖片需要提供多張不同尺寸的圖片,這會加大安裝包的大小。另外,需要對圖片做改動時,比如換個顏色,必須更換所有尺寸圖片。所以,建議儘量減少引入圖片,而通過使用shape、layer-list等自己畫,易於修改和維護,也減少了安裝包大小,適配性也更好。
bitmap標籤
可以通過bitmap標籤對圖片做一些設置,如平鋪、拉伸或保持圖片原始大小,也可以指定對齊方式。看看bitmap標籤的一些屬性吧:
- 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 設置是否抖動,圖片與屏幕的像素配置不同時會用到,比如圖片是ARGB 8888的,而屏幕是RGB565
-
android:filter 設置是否允許對圖片進行濾波,對圖片進行收縮或者延展使用濾波可以獲得平滑的外觀效果
-
android:tint 給圖片着色,比如圖片本來是黑色的,着色後可以變成白色
-
android:tileMode 設置圖片平鋪的方式,取值爲下面四種之一:
- disable 不做任何平鋪,默認設置
- repeat 圖片重複鋪滿
- mirror 使用交替鏡像的方式重複圖片的繪製
- clamp 複製圖片邊緣的顏色來填充容器剩下的空白部分,比如引入的圖片如果是白色的邊緣,那麼圖片所在的容器裏除了圖片,剩下的空間都會被填充成白色
-
android:alpha 設置圖片的透明度,取值範圍爲0.0~1.0之間,0.0爲全透明,1.0爲全不透明,API Level最低要求是11,即Android 3.0
-
android:mipMap 設置是否可以使用mipmap,但API Level最低要求是17,即Android 4.2
-
android:autoMirrored 設置圖片是否需要鏡像反轉,當佈局方向是RTL,即從右到左佈局時纔有用,API Level 19(Android 4.4)才添加的屬性
-
android:tileModeX 和tileMode一樣設置圖片的平鋪方式,只是這個屬性只設置水平方向的平鋪方式,這是API Level 21(Android 5.0)才添加的屬性
-
android:tileModeY 和tileMode一樣設置圖片的平鋪方式,只是這個屬性只設置垂直方向的平鋪方式,這是API Level 21(Android 5.0)才添加的屬性
-
android:tintMode 着色模式,也是API Level 21(Android 5.0)才添加的屬性
點九圖片
點九圖片文件擴展名爲:.9.png,通過點九圖片可以做局部拉伸,比如,一張圓角矩形圖片,我們不想讓它的四個邊角都被拉伸從而導致模糊失真,使用點九圖就可以控制拉伸區域,讓四個邊角保持完美顯示。效果如下圖:
畫點九圖一般用Android SDK工具集裏的draw9patch工具,只需要在四條邊畫黑線就可以了,如下圖所示:
拉伸區域就是圖片會被拉伸的部分,可以爲1個點,也可以爲一條線,甚至也可以爲斷開的幾個點或幾條線,總之,有黑點的地方就會被拉伸,沒有黑點的地方就不會被拉伸。而顯示內容區域其實就等於默認給使用的控件設置了padding,控件的內容只能顯示在內容區域內。
nine-patch標籤
使用nine-patch標籤可以對點九圖片做一些設置處理,不過可設置的屬性並不多:
- android:src 必填項,必須指定點九類型的圖片
- android:dither 設置是否抖動,圖片與屏幕的像素配置不同時會用到,比如圖片是ARGB 8888的,而屏幕是RGB565
- android:tint 給圖片着色,比如圖片本來是黑色的,着色後可以變成白色
- android:tintMode 着色模式,API Level 21(Android 5.0)才添加的屬性
- android:alpha 設置圖片的透明度,取值範圍爲0.0~1.0之間,0.0爲全透明,1.0爲全不透明,API Level最低要求是11
- android:autoMirrored 設置圖片是否需要鏡像反轉,當佈局方向是RTL,即從右到左佈局時纔有用,API Level 19(Android 4.4)才添加的屬性
color標籤
color標籤是drawable裏最簡單的標籤了,只有一個屬性:android:color,指定顏色值。這個標籤一般很少用,因爲基本都可以通過其他更方便的方式定義顏色。另外,顏色值一般都在colors.xml文件中定義,其根節點爲resources。看看兩者的不同:
<!-- 文件:res/drawable/white.xml --> <color xmlns:android="http://schemas.android.com/apk/res/android" android:color="#FFFFFF" />
<!-- 文件:res/values/colors.xml --> <resources> <color name="white">#FFFFFF</color> </resources>
引用的時候,前一種通過@drawable/white引用,後一種通過@color/white引用。
inset標籤
使用inset標籤可以對drawable設置邊距,其用法和View的padding類似,只不過padding是設置內容與邊界的距離,而inset則可以設置背景drawable與View邊界的距離。inset標籤的可設置屬性如下:
- android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標籤
- android:visible 設置初始的可見性狀態,默認爲false
- android:insetLeft 左邊距
- android:insetRight 右邊距
- android:insetTop 頂部邊距
- android:insetBottom 底部邊距
- android:inset 設置統一邊距,會覆蓋上面四個屬性,但API Level要求爲21,即Android 5.0
clip標籤
使用clip標籤可以對drawable進行裁剪,在做進度條時很有用。通過設置level值控制裁剪多少,level取值範圍爲0~10000,默認爲0,表示完全裁剪,圖片將不可見;10000則完全不裁剪,可見完整圖片。看看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時會裁剪左側,其他情況會同時裁剪左右兩側
那怎麼設置level呢?android沒有提供直接在xml裏設置level的屬性,這需要通過代碼去設置。舉例用法如下:
-
定義clip.xml:
<?xml version="1.0" encoding="utf-8"?> <clip xmlns:android="http://schemas.android.com/apk/res/android" android:clipOrientation="horizontal" android:drawable="@drawable/img4clip" android:gravity="left" />
-
在ImageView中引用:
<ImageView android:id="@+id/img" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/bg_img" android:src="@drawable/clip" />
-
在代碼中設置level:
ImageView img = (ImageView) findViewById(R.id.img); img.getDrawable().setLevel(5000); //level範圍值0~10000
scale標籤
使用scale標籤可以對drawable進行縮放操作,和clip一樣是通過設置level來控制縮放的比例。scale標籤可以設置的屬性如下:
- android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標籤
- android:scaleHeight 設置可縮放的高度,用百分比表示,格式爲XX%,0%表示不做任何縮放,50%表示只能縮放一半
- android:scaleWidth 設置可縮放的寬度,用百分比表示,格式爲XX%,0%表示不做任何縮放,50%表示只能縮放一半
- android:scaleGravity 設置drawable縮放後的位置,取值和bitmap標籤的一樣,就不一一列舉說明了,不過默認值是left
- android:useIntrinsicSizeAsMinimum 設置drawable原有尺寸作爲最小尺寸,設爲true時,縮放基本無效,API Level最低要求爲11
使用的時候,和clip一樣,用法如下:
-
定義scale.xml:
<?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/img4scale" android:scaleGravity="left" android:scaleHeight="50%" android:scaleWidth="50%" android:useIntrinsicSizeAsMinimum="false" />
-
在ImageView中引用:
<ImageView android:id="@+id/img" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/bg_img" android:src="@drawable/scale" />
-
在代碼中設置level:
ImageView img = (ImageView) findViewById(R.id.img); img.getDrawable().setLevel(5000); //level範圍值0~10000
level-list標籤
當需要在一個View中顯示不同圖片的時候,比如手機剩餘電量不同時顯示的圖片不同,level-list就可以派上用場了。level-list可以管理一組drawable,每個drawable設置一組level範圍,最終會根據level值選取對應的drawable繪製出來。level-list通過添加item子標籤來添加相應的drawable,其下的item只有三個屬性:
- android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標籤
- android:minLevel 該item的最小level值
- android:maxLevel 該item的最大level值
以下是示例代碼:
<?xml version="1.0" encoding="utf-8"?> <level-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/battery_low" android:maxLevel="10" android:minLevel="0" /> <item android:drawable="@drawable/battery_below_half" android:maxLevel="50" android:minLevel="10" /> <item android:drawable="@drawable/battery_over_half" android:maxLevel="99" android:minLevel="50" /> <item android:drawable="@drawable/battery_full" android:maxLevel="100" android:minLevel="100" /> </level-list>
那麼,當電量剩下10%時則可以設置level值爲10,將會匹配第一張圖片:
img.getDrawable().setLevel(10);
item的匹配規則是從上到下的,當設置的level值與前面的item的level範圍匹配,則採用。一般item的添加按maxLevel從小到大排序下來,此時minLevel可以不用指定也能匹配到。如上面代碼就可以簡化如下:
<?xml version="1.0" encoding="utf-8"?> <level-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/battery_low" android:maxLevel="10" /> <item android:drawable="@drawable/battery_below_half" android:maxLevel="50" /> <item android:drawable="@drawable/battery_over_half" android:maxLevel="99" /> <item android:drawable="@drawable/battery_full" android:maxLevel="100" /> </level-list>
但不能反過來將android:maxLevel="100"的item放在最前面,那樣所有電量都只匹配第一條了。
transition標籤
transition其實是繼承自layer-list的,只是,transition只能管理兩層drawable,另外提供了兩層drawable之間切換的方法,切換時還會有淡入淡出的動畫效果。示例代碼如下:
<?xml version="1.0" encoding="utf-8"?> <transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/on" /> <item android:drawable="@drawable/off" /> </transition>
transition標籤生成的Drawable對應的類爲TransitionDrawable,要切換時,需要主動調用TransitionDrawable的startTransition()方法,參數爲動畫的毫秒數,也可以調用reverseTransition()方法逆向切換。
((TransitionDrawable)drawable).startTransition(500); //正向切換,即從第一個drawable切換到第二個 ((TransitionDrawable)drawable).reverseTransition(500); //逆向切換,即從第二個drawable切換回第一個
rotate標籤
使用rotate標籤可以對一個drawable進行旋轉操作,在shape篇講環形時最後舉了個進度條時就用到了rotate標籤。另外,比如你有一張箭頭向上的圖片,但你還需要一個箭頭向下的圖片,這時就可以使用rotate將向上的箭頭旋轉變成一張箭頭向下的drawable。
先看看rotate標籤的一些屬性吧:
- 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
示例代碼如下,目標是將一張箭頭向上的圖片轉180度,轉成一張箭頭向下的圖片:
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_arrow" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="180" />
將它引用到ImageView裏,發現圖片根本沒有轉變。其實,要讓它可以旋轉,還需要設置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了。
animation-list標籤
通過animation-list可以將一系列drawable構建成幀動畫,就是將一個個drawable,一幀一幀的播放。通過添加item子標籤設置每一幀使用的drawable資源,以及每一幀持續的時間。示例代碼如下:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/anim1" android:duration="1000" /> <item android:drawable="@mipmap/anim2" android:duration="1000" /> <item android:drawable="@mipmap/anim3" android:duration="1000" /> </animation-list>
android:oneshot屬性設置是否循環播放,設爲true時,只播放一輪就結束,設爲false時,則會輪詢播放。
android:duration屬性設置該幀持續的時間,以毫秒數爲單位。
animation-list對應的Drawable類爲AnimationDrawable,要讓動畫運行起來,需要主動調用AnimationDrawable的start()方法。另外,如果在Activity的onCreate()方法裏直接調用start()方法會沒有效果,因爲view還沒有初始化完成是播放不了動畫的。
animated-rotate
rotate標籤只是將原有的drawable轉個角度變成另一個drawable,它是靜態的。而animated-rotate則會讓drawable不停地做旋轉動畫。
animated-rotate可設置的屬性只有四個:
- android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標籤
- android:pivotX 旋轉中心的X座標
- android:pivotY 旋轉中心的Y座標
- android:visible 設置初始的可見性狀態,默認爲false
示例代碼:
<?xml version="1.0" encoding="utf-8"?> <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/img_daisy" android:pivotX="50%" android:pivotY="50%" android:visible="false" />
寫在最後
至此,drawable資源基本都講完了,但還不是全部,Android 5.0新增的幾個標籤:animated-selector、vector、animated-vector、ripple,因爲還沒弄清楚具體的用法,而且也涉及到Material Design,所以不在本篇講解,後續做Material Design專題分享的時候會再詳細講解用法。
PS:selector標籤下的item其實還可以添加set標籤,這是添加動畫集的標籤,下一篇就將分享下一些常用動畫的製作。
原文地址: http://keeganlee.me/post/android/20150916