一、Drawable簡介
Drawable表示的是一種可以在Canvas上進行繪制的抽象概念。優(yōu)點:使用簡單,比自定義View成本低很多;非圖片類型的Drawable占用空間較小。
可以通過getIntrinsicWidth/getIntrinsicHeight這兩個方法獲取內部寬高。但并不是所有Drawable都有寬高:圖片Drawable的內部寬/高就是圖片的寬/高,但是顏色形成的Drawable并沒有寬/高的概念。注意,Drawable的內部寬/高不等同于它的大小,一般來說,Drawable沒有大小的概念,因其通常被用作View背景,Drawable會被拉伸至View的同等大小。
二、Drawable的分類
1、BitmapDrawable
表示的就是一張圖片,可以直接引用原始圖片即可,也可以通過XML描述它,從而設置更多效果。
<?xml version="1.0" encoding="utf-8"?>
<bitmap/nine-patch
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@[package:]drawable/drawable_resource"
android:antialias=["true" | "false"]
android:dither=["true" | "false"]
android:filter=["true" | "false"]
android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
"fill_vertical" | "center_horizontal" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"]
android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />
android:src
圖片資源idandroid:antialias
是否開啟圖片抗鋸齒功能。開啟后會讓圖片變得平滑,同時也會一定程度上降低圖片的清晰度,建議開啟;android:dither
是否開啟抖動效果。當圖片的像素配置和手機屏幕像素配置不一致時,開啟這個選項可以讓高質量的圖片在低質量的屏幕上還能保持較好的顯示效果,建議開啟。android:filter
是否開啟過濾效果。當圖片尺寸被拉伸或壓縮時,開啟過濾效果可以保持較好的顯示效果,建議開啟;-
android:gravity
當圖片小于容器的尺寸時,設置此選項可以對圖片進行定位。
android:tileMode
平鋪模式,有四種選項[“disabled” | “clamp” | “repeat” | “mirror”]。當開啟平鋪模式后,gravity屬性會被忽略。repeat是指水平和豎直方向上的平鋪效果;mirror是指在水平和豎直方向上的鏡面投影效果;clamp是指圖片四周的像素會擴展到周圍區(qū)域,這個比較特別。
NinePatchDrawable
表示一張.9格式的圖片,它和BitmapDrawable都表示一張圖片。用XML描述的方式也和BitmapDrawable一樣。在bitmap標簽中也可以使用.9圖。
2、ShapeDrawable
可以理解為通過顏色來構造的圖形,可以是純色或漸變的圖形。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"
android:radius="5dp"
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
<gradient
android:angle="0"
android:centerColor="#cccccc"
android:centerX="100"
android:centerY="20"
android:endColor="#abcdef"
android:gradientRadius="100dp"
android:startColor="#000000"
android:type="linear"
android:useLevel="false" />
<solid android:color="#cccccc" />
<stroke
android:width="1dp"
android:color="#cccccc"
android:dashGap="2dp"
android:dashWidth="50dp" />
-
android:shape
表示圖片的形狀,選項:rectangle(矩形)、oval(橢圓)、line(橫線)、ring(圓環(huán))。默認值是矩形,另外line和ring這兩個選項必須通過<stroke>標簽來指定寬度和顏色,否則看不到效果。 -
<corners>
表示shape的四個角的角度(圓角程度)。只適用于矩形shape。 -
<gradient>
與<solid>標簽相互排斥的,其中solid表示純色填充,而gradient表示漸變效果;
gradient有如下幾個屬性:
android:angle—— 漸變的角度,默認為0,其值必須是45的倍數,0表示從左往右,90表示從下到上。
android:centerX漸變的中心點的橫坐標
android:centerY漸變的中心點的縱坐標;
android:startColor漸變的起始色
android:centerColor漸變的中間色
android:endColor漸變的結束色
android:gradientRadius漸變半徑,僅當android:type=”radial”時有效。
android:type漸變的類型,有l(wèi)inear(線性漸變)、radial(鏡像漸變)、swepp(掃描線漸變)三種,默認是線性漸變。 -
<solid>
表示純色填充,通過android:color即可指定shape中填充的顏色。 -
<stroke>
android:width描邊的寬度
android:color描邊的顏色
android:dashWidth組成虛線的線段的寬度
android:dashGap組成虛線之間的間距。dashWidth和dashGap有任何一個為0,虛線效果都不能生效。 -
<padding>
表示空白,但不是shape的空白,而是包含它的View的空白。 -
<size>
shape的大小,有兩個屬性:android:width和android:height,分別表示shape的寬高。通過標簽指定寬高后,ShapeDrawable就有固定寬/高了。但是作為view的背景來說,shape還是會被拉伸或者縮小為view的大小。
3、LayerDrawable
一種層次化的Drawable集合,通過將不同的Drawable放置在不同層后達到一種疊加效果。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/res_haimei1"
android:bottom="10dp"
android:drawable="@mipmap/haimei1" //可以引用已有的Drawable資源
android:left="10dp"http://表示的是相對于View的上下左右偏移量
android:right="10dp"
android:top="10dp" />
<item
android:id="@+id/res_icon"
android:width="30dp"
android:height="30dp"
android:drawable="@mipmap/ic_launcher"
android:gravity="center" />
</layer-list>
一個layout-list中可以包含多個item,每個item表示一個Drawable。可以通過drawable屬性直接引用已有的Drawable資源,也可以在item自定義Drawable。
4、StateListDrawable
對應<selector>標簽。它也表示Drawable集合,每個Drawable對應View的一種狀態(tài),這樣系統(tǒng)就會根據View的狀態(tài)來選擇合適的Drawable。主要用于設置可點擊View的背景。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize="false"
android:dither="true"
android:variablePadding="false">
<item android:drawable="@mipmap/ic_launcher" android:state_pressed="true" />
<item android:drawable="@mipmap/haimei1" android:state_pressed="false" />
</selector>
-
android:constantSize
StateListDrawable的固有大小是否不隨著其狀態(tài)的變化而變化,因為不同的Drawable有不同的固有大小。true表示固有大小保持不變,這時它的固有大小是內部所有Drawable的固有大小的最大值。默認值為false。 - ``android:dither`
是否開啟抖動效果,默認true -
android:variablePadding
StateListDrawable的padding是否隨著狀態(tài)變化而變化。true表示變化,false表示padding是內部所有Drawable的padding的最大值。默認為false。
view的常見狀態(tài)
android:state_pressed 按下狀態(tài),Button按下之后沒有松開
android:state_focused View獲取了焦點
android:state_selected 用戶選擇了View,如RadioButton
android:state_checked 用戶選中了View,適用于CheckBox
android:state_enable View處于可用狀態(tài)
系統(tǒng)會從上到下的順序查找,直到找到第一條匹配的item。默認的item一般放在最后并且不添加任何狀態(tài),這樣當系統(tǒng)在之前的item無法選擇的時候,就會匹配默認的item,因為item的默認狀態(tài)不附帶任何狀態(tài),所以它可以適配任何狀態(tài)。
5、LevelListDrawable
對應<level-list>標簽。同樣表示Drawable集合,集合中的每個Drawable都會有一個等級的概念,根據等級不同來切換對于的Drawable。當它作為View的背景時,可以通過Drawable的setLevel方法來設置不同的等級從而切換具體的Drawable。level的值從0-10000,默認為0。
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="0" android:drawable="@drawable/ic_playmethod_normal" />
<item android:maxLevel="1" android:drawable="@drawable/ic_playmethod_repeat_list" />
<item android:maxLevel="2" android:drawable="@drawable/ic_playmethod_repeat_one" />
<item android:maxLevel="3" android:drawable="@drawable/ic_playmethod_random" />
</level-list>
6、TransitionDrawable
對應<transition>標簽。用于實現(xiàn)兩個Drawable之間淡入淡出的效果。
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/haimei2" />
<item android:drawable="@mipmap/haimei3" />
</transition>
TransitionDrawable drawable = (TransitionDrawable) imageView.getBackground();
drawable.startTransition(1000);
startTransition和reverseTransition方法實現(xiàn)淡入淡出的效果以及它的逆過程。
7、InsetDrawable
對應于<inset>標簽。它可以將其他Drawable內嵌到自己當中,并可以在四周留下一定的間距。當一個View希望自己的背景比自己的實際區(qū)域小的時候,可以采用InsetDrawable來實現(xiàn)。通過LayerDrawable也可以實現(xiàn)。
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@mipmap/haimei1"
android:insetBottom="10dp"http://內凹的大小
android:insetLeft="10dp"
android:insetRight="10dp"
android:insetTop="10dp">
<shape android:shape="rectangle">
<solid android:color="#abcdef" />
</shape>
</inset>
8、ScaleDrawable
對應于<scale>標簽,可以根據自己的level將指定的drawable縮放到一定比例。
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@color/blue"
android:level="1"
android:scaleGravity="center"
android:scaleHeight="20%"
android:scaleWidth="20%" />
android:scaleGravity屬性相當于gravity屬性。android:scaleHeight/scaleWidth 表示Drawable的縮放比例。
縮放公式: w -= (int) (w * (10000 - level) * mState.mScaleWidth / 10000)
可見,level越大,Drawable看起來越大;scaleHeight/scaleWidth越大,Drawable看起來越小。注意的是,level設置為0時,Drawable不可見。level不應超過10000。
9、ClipDrawable
對應于<clip>標簽,他可以根據自己當前的等級(level)來裁剪一個Drawable,裁剪方向可以通過Android:clipOrientation和android:gravity兩個屬性共同控制。
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="vertical\horizontal"
android:drawable="@drawable/bitmapdrawable"
android:gravity="bottom|top|left|right|center|fill|center_vertical
|center_horizontal|fill_vertical|fill_horizontal
|clip_vertical|clip_horizontal" />
clipOrientation表示裁剪方向。gravity需要和clipOrientation一起才能發(fā)揮作用。如下所示:
使用步驟:
- 定義ClipDrawable
- 布局文件引用
- 代碼控制level
ImageView imageClip = (ImageView) findViewById(R.id.image_clip);
ClipDrawable drawable = (ClipDrawable) imageClip.getDrawable();
drawable.setLevel(5000);
level=0的時候,表示完全裁剪,level=10000的時候表示完全不裁剪,level=5000的時候表示裁剪了一半。即等級越大,裁剪的區(qū)域越小。
三、自定義Drawable
Drawable的作用很單一:一個是最為ImageView中的圖像來顯示,另一個是作為View的背景(大部分情況)。
在第5章中,我們分析了View的工作原理,系統(tǒng)會調用Drawable的draw方法繪制view的背景。所以我們可以通過重寫Drawable的draw方法來自定義Drawable。但是,通常我們沒必要自定義Drawable,因為自定義Drawable無法在XML中使用。只有在特殊情況下可以使用自定義Drawable。
