一愁溜、概念
Drawable有很多種罐栈,它們都表示一種圖像的概念咕缎,但是它們又不全是圖片珠十,通過顏色也可以構造出各式各樣的圖像的效果。在實際開發(fā)中凭豪,Drawable常被用來作為View的背景使用焙蹭。Drawable一般都是通過XML來定義的,也可以通過代碼來創(chuàng)建嫂伞,用代碼創(chuàng)建會稍顯復雜孔厉。
Drawable的內部寬/高可以通過getIntrinsicWidth和getIntrinsicHeight這兩個方法來獲取,但是并不是所有的Drawable都有內部寬/高末早,比如一張圖片所形成的Drawable烟馅,它的內部寬/高就是圖片的寬/高,但是一個顏色所形成的Drawable就沒有寬/高的概念然磷。另外需要注意的是郑趁,Drawable的內部寬/高不等同于它的實際大小,當用作View的背景時姿搜,Drawable會被拉伸至View的同等大小寡润。
二、分類
1.BitmapDrawable
在實際開發(fā)中舅柜,我們可直接引用原始的圖片梭纹,也可通過XML的方式來描述它。
通過XML來描述的BitmapDrawable可以設置更多的效果致份,如下:
<?xml version="1.0" encoding="utf-8"?>
<bitmap
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:mipMap="[true | false]"
android:tileMode="[disabled | clamp | repeat | mirror]" />
android:src:圖片的資源id变抽。
android:antialias:是否開啟圖片抗鋸齒。開啟后會讓圖片變得平滑,同時也會一定程度上降低圖片的清晰度绍载。
android:dither:是否開啟抖動效果诡宗。開啟后可讓高質量的圖片在低質量的屏幕上能保持較好的顯示效果。
android:filter:是否開啟過濾效果击儡。當圖片尺寸被拉伸或壓縮時塔沃,開啟過濾效果可保持較好的顯示效果。
android:gravity:當圖片小于容器的尺寸時阳谍,設置此屬性對圖片進行定位蛀柴。此屬性的可選項較多,也可用|來組合使用矫夯。
android:mipMap:是否開啟紋理映射鸽疾。
android:tileMode:平鋪模式。
2.NinePatchDrawable
表示一張.9格式的圖片茧痒。.9圖片可自動地根據(jù)所需的寬/高進行相應的縮放并保證不失真肮韧。
在實際使用中可以直接引用.9圖片,也可以通過XML來描述它旺订。
通過XML描述如下:
<?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]" />
android:src:圖片的資源id弄企。
android:dither:是否開啟抖動效果。開啟后可讓高質量的圖片在低質量的屏幕上能保持較好的顯示效果区拳。
3.ShapeDrawable
可以理解為通過顏色來構造的圖形拘领,既可以是純色的圖形,也可以是具有漸變效果的圖形樱调。
<?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:topLeftRaidus="integer"
android:topRightRaidus="integer"
android:bottomLeftRaidus="integer"
android:bottomRightRaidus="integer" />
<gradient
android:angle="integer"
android:centerX="integer"
android:centerY="integer"
android:centerColor="color"
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" />
android:shape:圖形的形狀约素,有四個選項:rectangle(矩形)、oval(橢圓)笆凌、line(橫線)和ring(圓環(huán))圣猎,默認是rectangle。另外line和ring必須通過<stroke>標簽來指定線的寬度和顏色等信息乞而,否則無法達到預期的顯示效果送悔。
<corners>:表示shape的四個圓角的角度,只適用于矩形爪模,屬性如下:
android:radius:為四個角同事設定相同的角度欠啤。優(yōu)先級比以下4個屬性要低。
android:topLeftRadius:左上角的角度屋灌。
android:topRightRadius:右上角的角度洁段。
android:bottomLeftRadius:左下角的角度。
android:bottomRightRadius:右下角的角度共郭。
<solid>:純色填充祠丝,通過android:color指定填充的顏色疾呻。
<gradient>:漸變效果,與<solid>純色填充是互相排斥的纽疟,屬性如下:
android:angle:漸變的角度罐韩。默認為0憾赁,其值必須為45的倍數(shù)污朽。此角度會影響漸變的方向,0表示從左到右龙考,90表示從下到上蟆肆。
android:centerX:漸變的中心點的X坐標。
android:centerY:漸變的中心點的Y坐標晦款。
android:startColor:漸變的起始色炎功。
android:centerColor:漸變的中間色。
android:endColor:漸變的結束色缓溅。
android:gradient:漸變半徑蛇损。僅當android:type="radial"時有效。
android:useLevel:一般為false坛怪,當Drawable作為StateListDrawable時為true淤齐。
android:type:漸變的類別。有l(wèi)inear(線性漸變)袜匿、radial(徑向漸變)更啄、sweep(掃描線漸變),默認為linear居灯。
<stroke>:描邊祭务。
android:width:描邊的寬度。
android:color:描邊的顏色怪嫌。
android:dashWidth:虛線的寬度义锥。
android:dashGap:虛線之間的間隔。
<padding>:空白岩灭,表示的不是shape的空白拌倍,而是包含它的View的空白,有l(wèi)eft川背、top贰拿、right、bottom四個屬性熄云。
<size>:大小膨更。有兩個屬性:android:width和android:height,分別表示shape的內部寬/高缴允,但是一般來說它并不是shape最終顯示的大小荚守。也就是說珍德,通過<size>標簽可以設置ShapeDrawable的內部寬/高,但是作為View的背景時矗漾,shape還會被拉伸或者縮小為View的大小锈候。
4.LayerDrawable
對應<layer-list>標簽,表示一種層次化的Drawable集合敞贡,通過將不同的Drawable放置在不同的層上面從而達到一種疊加后的效果泵琳。
<?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" />
<!-- 其他item -->
</layer-list>
一個layer-list可包含多個item,每個item表示一個Drawable誊役』窳校可在android:drawable中引用一個現(xiàn)有的Drawable資源,也可在<item>中自定義Drawable蛔垢。
默認情況下击孩,layer-list中的所有Drawable都會被縮放至View的大小∨羝幔可設置Drawable相對于View的上下左右偏移量巩梢。另外對于bitmap,需要使用其android:gravity來控制圖片的顯示效果艺玲。
layer-list有層次的概念括蝠,下面的item會覆蓋上面的item。通過合理的分層板驳,可實現(xiàn)一些特殊的疊加效果又跛。
5.StateListDrawable
對應<selector>標簽,表示一個Drawable的集合若治。每個Drawable對應著View的一種狀態(tài)慨蓝,系統(tǒng)會根據(jù)View的狀態(tài)來選擇合適的Drawable。StateListDrawable主要用于設置可單擊的View的背景端幼,最常見的是Button礼烈。
<?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]" />
<!-- 其他item -->
</selector>
android:constantSize:StateListDrawable的內部寬/高是否不隨著其狀態(tài)的改變而改變,因為狀態(tài)的改變會導致StateListDrawable切換到具體的Drawable婆跑,而不同的Drawable具有不同的內部寬/高此熬。默認為false,即隨著狀態(tài)的改變而改變大小滑进。若為true犀忱,則表示其內部所有Drawable的內部寬/高的最大值。
android:dither:是否開啟抖動效果扶关。開啟此選項可以讓圖片在低質量的屏幕上仍然獲得較好的顯示效果阴汇。此選項默認值為true。
android:variblePadding:StateListDrawable的padding是否隨著其狀態(tài)的改變而改變节槐。默認為false搀庶,表示其內部所有Drawable的padding的最大值拐纱。若為true,表示會隨著狀態(tài)的改變而改變哥倔。
<item>:表示某種狀態(tài)下的一個具體的Drawable秸架。用android:drawable指定一個現(xiàn)有Drawable的資源id,剩下的屬性表示的是View的各種狀態(tài)咆蒿。
系統(tǒng)會按照從上到下的順序查找东抹,直至查找到第一條匹配的item。一般來說蜡秽,默認的item都應該放在selector的最后一條府阀,并且不附帶任何的狀態(tài)。
6.LevelListDrawable
對應<level-list>標簽芽突,表示一個Drawable集合,集合中的每個Drawable都有一個等級的概念董瞻。根據(jù)不同的等級寞蚌,LevelListDrawable會切換為對應的Drawable。
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@[package:]drawable/drawable_resource"
android:maxLevel="integer"
android:minLevel="integer" />
<!-- 其他item -->
</level-list>
7.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="@[package:]drawable/drawable_resource"
android:id="@[+][package:]id/resource_name"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"
android:left="dimension" />
<!-- 另一個item,注意transition只包含兩個item -->
</transition>
常將TransitionDrawable作為View的背景抄伍,再調用它的startTransition和reverseTransition方法來實現(xiàn)淡入淡出效果以及它的逆過程艘刚。代碼如下:
ImageView imageview = (ImageView) findViewById(R.id.imageview);
TransitionDrawable drawable = (TransitionDrawable) imageview.getBackground();
drawable.startTransition(1000);
8.InsetDrawable
對應<inset>標簽,可將其他Drawable內嵌到自己當中截珍,并可在四周留出一定的間距攀甚。當一個View希望自己的背景比自己的實際區(qū)域小的時候,可采用InsetDrawable來實現(xiàn)岗喉,同時我們知道秋度,通過LayoutDrawable也可以實現(xiàn)這種效果。
<?xml version="1.0" encoding="utf-8"?>
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@[package:]drawable/drawable_resource"
android:inset="dimension"
android:insetTop="dimension"
android:insetRight="dimension"
android:insetBottom="dimension"
android:insetLeft="dimension" />
9.ScaleDrawable
對應<scale>標簽钱床,將Drawable縮放到一定比例荚斯。
<?xml version="1.0" encoding="utf-8"?>
<scale
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@[package:]drawable/drawable_resource"
android:scaleGravity="[top | bottom | left | right |
center_vertical | center_horizontal | center |
fill_vertical | fill_horizontal | fill |
clip_vertical | clip_horizontal]"
android:scaleWidth="percentage"
android:scaleHeight="percentage" />
縮放比例越大,內部的Drawable就越胁榕啤事期;level越大,內部的Drawable就越大纸颜。
由于level默認為0兽泣,若level為0時,ScaleDrawable不可見懂衩。
10.ClipDrawable
對應<clip>標簽撞叨,用來裁剪另一個Drawable金踪。
<?xml version="1.0" encoding="utf-8"?>
<clip
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@[package:]drawable/drawable_resource"
android:clipOrientation="[vertical | horizontal]"
android:gravity="[top | bottom | left | right |
center_vertical | center_horizontal | center |
fill_vertical | fill_horizontal | fill |
clip_vertical | clip_horizontal]" />
android:clipOrientation:表示裁剪方向,可選為水平和豎直牵敷。
android:gravity:表示對齊方式胡岔,需要和clipOrientation一起發(fā)揮作用。
ClipDrawable的裁剪程度由level控制枷餐,調用setLevel方法可修改此值靶瘸。其取值范圍為0~10000。0表示完全裁剪毛肋,即整個Drawable都不可見怨咪;而10000表示不裁剪,即整個Drawable都可見润匙。
三诗眨、自定義Drawable
Drawable的工作原理很簡單,其核心就是draw方法孕讳。系統(tǒng)會調用Drawable的draw方法來繪制View的背景或ImageView的圖像匠楚,我們可通過重寫其draw方法來實現(xiàn)自定義Drawable。通常我們沒有必要去自定義Drawable厂财,因為無法在XML中使用自定義Drawable芋簿,這就降低了其使用范圍。
創(chuàng)建自定義Drawable璃饱,必須重寫其draw与斤、setAlpha、setColorFilter荚恶、getOpacity等方法撩穿。以下為自定義Drawable示例:
//CustomDrawable
public class CustomDrawable extends Drawable {
private Paint mPaint;
public CustomDrawable(int color) {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(color);
}
@Override
public void draw(Canvas canvas) {
final Rect rect = getBounds();
float cx = rect.exactCenterX();
float cy = rect.exactCenterY();
canvas.drawCircle(cx, cy, Math.min(cx, cy), mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mPaint.setColorFilter(colorFilter);
invalidateSelf();
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
//MainActivity
CustomDrawable drawable = new CustomDrawable(Color.BLUE);
imageView.setBackgroundDrawable(drawable);
若自定義的Drawable有內部寬/高時,要重寫getIntrinsicWidth和getIntrinsicHeight這兩個方法裆甩,因為它們會影響到View的wrap_content布局冗锁。
需要注意的是,Drawable的內部寬/高不等同于Drawable的實際大小嗤栓《澈樱可通過getBounds方法獲得Drawable的實際大小,一般與它的View尺寸相同茉帅。