一侦厚、Drawable 簡介
Drawable 是一個抽象類,它是所有 Drawable 對象的基類梢灭,每個具體的 Drawable 都是它的子類乎折,比如 ShapeDrawable、BitmapDrawable 等靶累,Drawable 層次關(guān)系如圖:
如何使用 Drawable:
- 一般都是通過 XML 來定義
- 也可以在代碼中創(chuàng)建
關(guān)于 Drawable 的內(nèi)部寬/高:
- 通過 getIntrinsicWidth 和 getIntrinsicHeight 獲取
- 不是所有的 Drawable 都有內(nèi)部寬/高腺毫,比如一個顏色所形成的 Drawable
- Drawable 的內(nèi)部寬/高不等于它的大小,一般來說 Drawable 是沒有大小概念的挣柬。當用作 View 的背景時潮酒,Drawable 會被拉伸至 View 的同等大小
二、Drawable 的分類
1邪蛔、BitmapDrawable
這是最簡單的 Drawable急黎,它表示一張圖片。我們可以在代碼中引用原始的圖片侧到,也可以通過 XML 的方式來描述它勃教,通過 XML 來描述的 BitmapDrawable 可以設(shè)置更多的效果:
bitmap
|- android:src="@drawable/res_id"
|- 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 | repeat | mirror | clamp]"
-
android:src
圖片的資源 id
-
android:antialias
是否開啟圖片抗鋸齒功能。開啟后圖片會變得更加平滑床牧,同時會在一定程度上降低圖片的清晰度荣回,但是這個降低的幅度較低可以忽略,應(yīng)此需要開啟
-
android:dither
是否開啟抖動效果戈咳。讓高質(zhì)量的圖片在低質(zhì)量的屏幕上還能保持較好的顯示效果心软,應(yīng)此需要開啟
-
android:filter
是否開啟過濾效果。當圖片尺寸被拉伸或者壓縮時著蛙,開啟過濾效果可以保持較好的顯示效果删铃,應(yīng)此需要開啟
-
android:gravity
當圖片小雨容器的尺寸時,設(shè)置此選項可以對圖片進行定位踏堡。不同選項可以通過 "|"來組合使用
-
android:tileMode
平鋪模式猎唁。disable 為關(guān)閉平鋪模式,也是默認值顷蟆;repeat 表示水平和豎直方向上的平鋪效果诫隅;mirror 表示水平和豎直方向上的鏡面投影效果腐魂;clamp 表示圖片四周的像素會擴散到周圍區(qū)域
使用方法:
- xml 定義:
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:antialias="true"
android:dither="true"
android:filter="true"
android:src="@drawable/haha" />
- 代碼中定義
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.haha);
BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), bitmap);
bitmapDrawable.setAntiAlias(true);
bitmapDrawable.setDither(true);
ivShow.setImageDrawable(bitmapDrawable);
2、NinePatchDrawable
它表示一張 .9 格式的圖片逐纬,該格式可以自動根據(jù)所需的寬/高進行相應(yīng)的縮放并且保證不失真
<nine-patch
|- src="@drawable/9_png_resid"
|- dither="[true | false]" />
它在 XML 中屬性的含義與 BitmapDrawable 中對應(yīng)屬性的含義相同蛔屹。另外,在 bitmap 標簽中也可以使用 .9 圖片豁生,即 BitmapDrawable 也可以代表一個 .9 格式圖片
3兔毒、ShapeDrawable
ShapeDrawable 也是一種很常見的 Drawable,可以理解為通過顏色來構(gòu)造的圖形甸箱,語法如下所示:
<?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" />
</shape>
-
android:shape
表示圖形的形狀育叁,有四個選項:rectangle(矩形)、oval(橢圓)芍殖、line(橫線)豪嗽、ring(圓環(huán)),它的默認值是矩形豌骏。
另外 line 和 ring 這兩個選項必須要通過 <stroke> 標簽來指定線的寬度和顏色昵骤。
最后,針對 ring 這個形狀肯适,有 5 個特殊的屬性:
-
< corners >
表示 shape 的四個角的角度变秦,它只適用于矩形 shape,用 px 表示框舔,它有如下五個屬性:
-
android:radius
:為四個角同事設(shè)定相同的角度蹦玫。優(yōu)先級比以下4個屬性要 -
android:topLeftRadius
:左上角的角度。 -
android:topRightRadius
:右上角的角度刘绣。 -
android:bottomLeftRadius
:左下角的角度樱溉。 -
android:bottomRightRadius
:右下角的角度。
-
-
< gradient >
它與 <solid> 標簽互斥纬凤,其中 solid 表示純色填充福贞,gradient 表示漸變效果,gradient 有如下幾個屬性:
-
android:angle
:漸變的角度停士。默認為0挖帘。值必須為45的倍數(shù)。0表示從左到右恋技,90表示從下到上拇舀。 -
android:centerX
:漸變的中心點的X坐標。 -
android:centerY
:漸變的中心點的Y坐標蜻底。 -
android:startColor
:漸變的起始色骄崩。 -
android:centerColor
:漸變的中間色。 -
android:endColor
:漸變的結(jié)束色。 -
android:gradientRadius
:漸變半徑要拂。僅當android:type="radial"時有效 -
android:useLevel
:一般為false抠璃,當 Drawable 作 StateListDrawable 時為true -
android:type
:漸變的類別,可選值:linear(線性漸變)脱惰、radial(徑向漸變)鸡典、sweep(掃描式線漸變)
-
-
< solid >
純色填充,通過 android:color 即可指定 shape 中填充的顏色
-
< stroke >
Shape 的描邊枪芒,有如下幾個屬性:
-
android:width
:描邊的寬度,越大則 shape 的邊緣線久看會看起越粗 -
android:color
:描邊的顏色 -
android:dashWidth
:組成虛線的線段的寬度 -
android:dashGap
:組成虛線之間的線段之間的間隔谁尸,越大則虛線看起來空隙越大
如果
android:dashWidth
和android:dashGap
有任何一個為 0舅踪,則虛線效果將不能生效。<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#ff0000" /> <stroke android:width="3dp" android:color="#00ff00" android:dashWidth="2dp" android:dashGap="2dp" /> </shape>
-
-
< padding >
與四周空白的距離
-
< size >
設(shè)置圖形的固有大小良蛮,非最終大小
3抽碌、LayerDrawable
LayerDrawable 對應(yīng)的 XML 標簽是 < 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=""
android:id=""
android:bottom=""
android:left=""
android:right=""
android:top="" />
</layer-list>
一個 layer-list 可以包含多個 item,每個 item 表示一個 Drawable皮胡。常用屬性如下所示:
- android:bottom痴颊、android:left、android:right屡贺、android:top蠢棱。分別代表表示 Drawable 相對于 View 的上下左右的偏移量
- 可以通過 android:drawable 來直接引用一個已有的 Drawable 資源
實現(xiàn) bitmap 的簡單疊加:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_launcher_foreground" />
<item
android:bottom="50dp"
android:drawable="@drawable/ic_launcher_foreground"
android:left="50dp" />
<item
android:bottom="100dp"
android:drawable="@drawable/ic_launcher_foreground"
android:left="100dp" />
<item
android:bottom="150dp"
android:drawable="@drawable/ic_launcher_foreground"
android:left="150dp" />
</layer-list>
效果圖:
5、StateListDrawable
stateListDrawable 對應(yīng)于 < slector >標簽甩栈,它也表示 Drawable 集合泻仙,每個 Drawable 都對應(yīng)著 View 的一種狀態(tài),它的語法如下所示:
selector
|-constantSize="[true | false]"
|-dither="[true | false]"
|-variablePadding="[true | false]"
|- item
| |- drawable="@drawable/drawable_id"
| |- state_pressed="[true | false]"
| |- state_focused="[true | false]"
| |- state_selected="[true | false]"
| |- state_hovered="[true | false]"
| |- state_checked="[true | false]"
| |- state_checkable="[true | false]"
| |- state_enabled="[true | false]"
| |- state_activated="[true | false]"
| |- state_window_focused="[true | false]"
|
-
android:constanSize
StateListDrawable 的固有大小是否不隨著其狀態(tài)的改變和改變量没,因為不同狀態(tài)的 Drawable 的固有大小不同玉转。True 表示 StateListDrawable 的固有大小保持不變,此時它的固有大小是內(nèi)部所有 Drawable 的固有大小的最大值殴蹄,false 則會隨著狀態(tài)的改變而改變究抓。此默認值為 false。
-
android:dither
是否開啟抖動效果袭灯。此選項默認為 ture漩蟆。
-
android:variablePadding
表示 StateListDrawable 的 padding 是否隨著其狀態(tài)的改變而改變。true 表示會隨著狀態(tài)的改變而改變妓蛮,false 表示 padding 是內(nèi)部所有 Drawable 的 padding 的最大值怠李。此選項默認值為 false,并且不建議開啟此選項。
< item >標簽表示一個具體的 Drawable捺癞,其中 android:drawable 是一個已有 Drawable 的資源id夷蚊,剩下的屬性表示 View 的各狀態(tài),常見狀態(tài)如下:
示例代碼如下:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/button_focused" android:state_focused="true" />
<item android:drawable="@drawable/button_normal" />
</selector>
系統(tǒng)會按照從上到下的順下查找髓介,直到查找到第一條匹配的 item惕鼓。一般來說,默認的 item 都應(yīng)該放在 selecoor 的最后一條并不附帶任何狀態(tài)唐础。
6箱歧、LevelListDrawable
對應(yīng)于 < level-list > 標簽,它表示一個 Drawable 集合一膨,集合中的每個 Drawable 都對應(yīng)一個等級呀邢。根據(jù)不同的等級,LevelListDrawable 會切換為對應(yīng)的 Drawable豹绪,它的語法如下:
level-list
|- item
| |- drawable="@drawable/drawable_id"
| |- maxLevel="integer"
| |- minlevel="integer"
-
android:maxLevel
對應(yīng)最大值价淌,取值范圍 0~10000,默認為0
-
android:minlevel
對應(yīng)最小值瞒津,取值范圍 0~10000蝉衣,默認值為0
//在Drawable文件夾中創(chuàng)建bg_level.xml
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="1" android:drawable="@drawable/image1" />
<item android:maxLevel="2" android:drawable="@drawable/image2" />
<item android:maxLevel="3" android:drawable="@drawable/image3" />
</level-list>
//在activity_main.xml中設(shè)置為ImageView背景
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bg_level"/>
//在MainActivity調(diào)用setImageLevel()
ImageView imageView = (ImageView) findViewById(R.id.image);
imageView.setImageLevel(2);
運行結(jié)果:ImageView的背景為image2
7、TransitionDrawable
對應(yīng)于 < transition > 標簽巷蚪,用于實現(xiàn)兩個 Drawable 之間的淡入淡出效果病毡,語法如下所示:
transition
|- item
| |- drawable="@drawable/drawable_id"
| |- id="@+id/xxx_id"
| |- top="dimension"
| |- left="dimension"
| |- right="dimension"
| |- bottom="dimension"
|
上面語法中的屬性都已經(jīng)介紹過了,其中 android:top屁柏、left剪验、right、bottom 仍然表示 Drawable 四周的偏移量前联。
- 使用方法:
//在Drawable文件夾中創(chuàng)建bg_tran.xml
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/image1"/>
<item android:drawable="@drawable/image2"/>
</transition>
//在activity_main.xml中設(shè)置為ImageView背景
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/bg_tran"/>
//在MainActivity調(diào)用startTransition()
ImageView imageView = (ImageView) findViewById(R.id.image);
TransitionDrawable td = (TransitionDrawable) imageView.getDrawable();
td.startTransition(3000);
上面通過 startTransition 和 reverseTransition 方法實現(xiàn)淡入淡出的效果以及它的逆過程功戚。
8、InsetDrawable
對應(yīng)于 < inset > 標簽似嗤,它可以將其他 Drawable 內(nèi)嵌到自己當中啸臀,并可以在四周留出一定的間距。語法如下所示:
inset
|- drawable="@drawable/drawable_id"
|- visible="[true | false]"
|- insetTop="dimension"
|- insetLeft="dimension"
|- insetRight="dimension"
|- insetBottom="dimension"
|
- android:drawable烁落,代表所引用的資源id
- android:insetTop 乘粒,表示距離容器的上邊距。其他同理
- android:visible伤塌,是否留有邊距
當一個 View 希望自己的背景比自己的實際區(qū)域小時灯萍,可以用采用 InsetDrawable 來實現(xiàn),示例如下:
// 在 drawable 文件夾下創(chuàng)建 inset_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/image"
android:insetLeft="10dp"
android:insetTop="20dp"
android:insetRight="30dp"
android:insetBottom="40dp"
android:visible="true" />
// 引用 inset_drawable
<View
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@drawable/inset_drawable" />
效果圖:
9每聪、ScaleDrawable
對應(yīng)于 < scale > 標簽旦棉,它可以根據(jù)自己的等級將制定的 Drawable 縮放到一定比例齿风,語法如下:
scale
|- drawable="@drawable/drawable_id"
|- scaleGravity="[top | bottom | left | right |
center_vertical | center_horizontal | center |
fill_vertical | fill_horizontal | fill |
clip_vertical | clip_horizontal]"
|- scaleWidth="percentage"
|- scaleHeight="percentage"
|
- android:drawable,表示引用的資源id
- android:scaleGravity绑洛,等同于 bitmapDrawable 的 android:gravity
- android:scaleWidth/android:scaleHeight救斑,表示縮放比例,用百分比形式表示
示例:將一張圖片縮小為原來的 30%真屯,代碼如下:
// 在 drawable 文件夾下創(chuàng)建 inset_drawable.xml
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/image"
android:scaleWidth="70%"
android:scaleHeight="70%"
android:scaleGravity="center" />
// 引用 inset_drawable.xml
<ImageView
android:id="@+id/image"
android:layout_width="300dp"
android:layout_height="300dp"
android:src="@drawable/scale_drawable" />
// 在代碼中設(shè)置 ScaleDrawable 的 level
ImageView mImageView = findViewById(R.id.image);
ScaleDrawable drawable = (ScaleDrawable) mImageView.getDrawable();
drawable.setLevel(1);
注意:
- level 的取值范圍為 0~1000脸候,默認值為 0
- 若 level 為 0,那么 scaleDrawable 是不可見的绑蔫,所以需要在代碼中 通過 setLevel 設(shè)置
10运沦、ClipDrawable
對應(yīng)于 < clip > 標簽,它可以根據(jù)自己當前的等級來裁剪另一個 Drawable配深,裁剪方向通過 android:clipOrientation 和 android:gravity 這兩個屬性來共同控制携添,語法如下:
scale
|- drawable="@drawable/drawable_id"
|- gravity="[top | bottom | left | right |
center_vertical | center_horizontal | center |
fill_vertical | fill_horizontal | fill |
clip_vertical | clip_horizontal]"
|- clipOrientation="[vertical | horizontal]"
|
其中 clipOrientation 表示裁剪方向,有水平和豎直兩個方向凉馆。gravity 比較復(fù)雜,需要和 clipOrientation 一起才能發(fā)揮作用亡资,另外它可通過 “|” 來組合使用
使用示例:
// 在 drawable 文件夾中創(chuàng)建 clip_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="vertical"
android:drawable="@drawable/image"
android:gravity="bottom" />
// 使用 clip_drawable.xml 作為圖像
<ImageView
android:id="@+id/image"
android:layout_width="300dp"
android:layout_height="300dp"
android:src="@drawable/clip_drawable" />
// 在代碼中設(shè)置等級
mImageView = findViewById(R.id.image);
ClipDrawable drawable = (ClipDrawable) mImageView.getDrawable();
drawable.setLevel(7000);
效果圖:
對于 ClipDrawable 來說澜共,Drawable 的等級(level)為 0 時表示完全裁剪,即整個 Drawable 都不見了锥腻,而等級 10000 表示不裁剪嗦董。
三、自定義 Drawable
- Drawable 的使用范圍單一瘦黑,一個是作為 ImageView 中的圖像來顯示京革,另外一個就是作為 View 的背景,大多數(shù)情況下 Drawable 都是以 View 的背景這種形式出現(xiàn)的幸斥。
- 可以通過重寫 Drawable 的 draw 方法來自定義 Drawable
- 但是匹摇,我們通常沒必要去自定義 Drawable,因為自定義的 Drawable 無法復(fù)用
如果在某些特殊情況下甲葬,我們還是想要自定義 Drawable廊勃,也可以,下面給出示例代碼:
//自定義Drawable
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;
}
}
在自定義 Drawable 時注意:
- draw经窖、setAlpha坡垫、setColorFilter、getOpacity 這幾個方法都是必須要實現(xiàn)的
- 當自定義 Drawable 時繪制一張圖片時画侣,最好重寫 getIntrinsicWidth 和 getIntrinsicHeight 方法冰悠。(上面例子中 Drawable 是顏色填充,所以沒有固定大小配乱,就不需要重寫)
- Drawable 的內(nèi)部大小不等于 Drawable 的實際區(qū)域大小溉卓,Drawable 的實際區(qū)域大小可以通過它的 getBounds 方法來得到皮迟,一般來說和它的 View 的尺寸相同