6.1 Drawable 簡介
Android 中的 Drawable 表示一種可以在 Canvas 上進行繪制的抽象的概念,比如顏色和圖片都可以是一個 Drawable。
6.2 Drawable 的分類
6.2.1 BitmapDrawable
BitmapDrawable 表示一張圖片,可以用原始圖片顯示,也可以用 XML 的方式。
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/image1" //圖片資源 id
android:antialias="true" //抗鋸齒
android:dither="true" //抖動
android:filter="true"
android:gravity="center"
android:mipMap="false"
android:tileMode="disabled">
</bitmap>
-
android:src
圖片資源 id -
android:antialias
抗鋸齒,開啟后讓圖片變得平滑。 -
android:dither
抖動效果,開啟后圖像在不同屏幕上的顯示效果越逼真。 -
android:filter
過濾效果,當圖片尺寸被拉伸,開啟過濾效果可以保持較好的顯示效果。 -
android:gravity
對圖片在容器中定位。 -
android:mipMap
這一種圖像相關的處理技術,也叫紋理映射,比較抽象,默認 false,不用深究。 - android:tileMode
- disabled :禁用
- repeat :水平和豎直方向上的平鋪效果
- mirror :水平和豎直方向上的鏡面投影效果
- clamp :四周的像素擴散到周圍
6.2 ShapeDrawable
ShapeDrawable 可以理解為通過顏色來構造的圖形,可以是純色或者具有漸變的圖形。需要注意的是<shape>標簽創建的 Drawable 其實體類是 GradientDrawable。
-
android:shape
表示圖形的形狀,有四個選項: - rectangle(矩形):默認選擇
- oval(橢圓)
- line(橫線):必須通過<stroke>標簽來指定線的寬度和顏色等信息
- ring(圓環):必須通過<stroke>標簽來指定線的寬度和顏色等信息
value | Desciption |
---|---|
android:innerRadius | 圓環的內半徑,和 android:innerRadiusRatio 同時存在時,以android:innerRadius為準 |
android:thickness | 圓環的厚度,即半徑減去內半徑的大小 |
android:innerRadiusRatio | 內半徑占整個 Drawable 寬度的比例,默認值為 9。如果為 n,那么內半徑 = 寬度 / n |
android:thicknessRatio | 厚度占整個 Drawable 寬度的比例,默認值為 3,,如果為 n,那么厚度 = 寬度 / n |
android:useLevel | 一般都應該使用 false |
<corners>
表示 shape 四個角的角度,只適用于矩形 shape,用 px 來表示:android:radius —— 為四個角同時設定相同的角度;
android:topRightRadius —— 設定右上角的角度;
android:bottomLeftRadius —— 設定左下角的角度;
android:bottomRightRadius —— 設定右下角的角度;
<gradient>
它與<soild>標簽是互相排斥的,soild 表示純色填充,gradient 表示漸變效果。android:angle —— 漸變的角度,默認為 0,其值必須為 45 的背熟,0 表示從左到右,90 表示從上到下。
android:centerX —— 漸變的中心點的橫坐標;
android:centerY —— 漸變的中心點的縱坐標
android:startColor —— 漸變的起始色
android:centerColor —— 漸變的中間色
android:endColor —— 漸變的結束色
android:gradientRadius —— 漸變的半徑,僅當 android:type = “radial” 時有效。
android:useLevel —— 一般為 false,當 Drawable 作為 StateListDrawable 使用時為 true;
android:type —— 漸變的類別,linear(線性漸變)、radial(徑向漸變)、sweep(掃描線漸變)
<soild>
純色填充<stroke>
Shape 的描邊android:width —— 描邊的寬度;
android:color —— 描邊的顏色;
android: dashWidth —— 組成虛線的線段的寬度;
android:dashGap —— 組成虛線的線段之間的間隔;
<padding>
四個屬性:android:left、top、right、bottom<size>
shape 的大小,有兩個屬性:android:width、height,表示 shape 的固有大小,但作為 View 的背景時,還是會被顯示為 View 的大小。
6.2.3 LayerDrawable
LayerDrawable 對應的 XML 標簽是<layer-list> ,通過不同的 Drawable 放置不再通的層上面從而達到一種疊加后的效果。
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle" >
<solid android:color="#0ac39e" />
</shape>
</item>
<item android:bottom="6dp">
<shape android:shape="rectangle" >
<solid android:color="#ffffff" />
</shape>
</item>
<item
android:bottom="1dp"
android:left="1dp"
android:right="1dp">
<shape android:shape="rectangle" >
<solid android:color="#ffffff" />
</shape>
</item>
</layer-list>
6.2.4 StateListDrawable
StateListDrawable 對應<selector> 標簽,表示 Drawable 的集合。
android:constantSize
StateListDrawable 的固有大小是否隨著其狀態的改變而改變,因為狀態的改變而切換到具體的 Drawable,為 true 則表示 StateListDrawable 的固有大小是所有 Drawable 最大值并且保持不變,默認為 false,會改變。android:dither
開啟抖動效果,默認為 true,開啟后在低質量的屏幕上仍有較好的顯示效果。android:variablePadding
StateListDrawable 的 padding 是否隨其狀態的改變而改變,true 是改變,默認為 false(推薦)。<item>
表示一個具體的 Drawable。
狀態 | 含義 |
---|---|
android:state_proessed | 表示按下狀態 |
android:state_focused | 表示 View 已經獲取了焦點 |
android:state_selected | 表示用戶選擇了焦點 |
android:state_checked | 表示用戶選中了 View,一般適用于 CheckBox 這類。 |
android:state_enabled | 表示 View 當前處于可用狀態 |
6.2.5 LeveListDrawable
LeveListDrawable 對應于 <level-list> 標簽,表示一個 Drawable 集合,根據其中的 level 來切換對應的 Drawable。
- 作為 View 的背景:通過 setLevel 來切換
- 作為 ImageView 的前景 Drawable:通過 ImageView.setImageLevel 來切換。
6.2.6 TransitionDrawable
TransitionDrawable 對應于<transiton>標簽,用于實現兩個 Drawable 之間的淡入淡出效果。
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bitmap_drawable_clamp"/>
<item android:drawable="@drawable/bitmap_drawable_mirror"/>
</transition>
TransitionDrawable drawable = (TransitionDrawable) button.getBackground();
drawable.startTransition(3000);
6.2.7 InsetDrawable
InsetDrawable 對應于<inset>標簽,它可用將其他 Drawable 內嵌到自己當中,并可用在四周流出一定的間距。
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetBottom="15dp"
android:insetLeft="15dp"
android:insetRight="15dp"
android:insetTop="15dp" >
<shape android:shape="rectangle" >
<solid android:color="#ff0000" />
</shape>
</inset>
6.2.8 ScaleDrawable
ScaleDrawable 對應于<scale>標簽,下面案例:顯示 30% 的大小
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/image1"
android:scaleHeight="70%"
android:scaleWidth="70%"
android:scaleGravity="center" />
必須設置一個比 大于 0 小于 10000 的數字,否則無效
ScaleDrawable drawable = (ScaleDrawable) button.getBackground();
drawable.setLevel(1);
6.2.9 ClipDrawable
ClipDrawable 對應于<clip>標簽,它可以根據自己當前的等級(level)來裁剪另一個 Drawable。
android:clipOrientation
horizontal:橫向
vertical:豎向
android:gravity
選項 | 含義 |
---|---|
top | 將內部的 Drawable 放在容器的頂部,不改變它的大小。如果為豎直裁剪,那么從底部開始裁剪。 |
bottom | 將內部的 Drawable 放在容器的底部,不改變它的大小。如果為豎直裁剪,那么從頂部開始裁剪 |
left | 將內部的 Drawable 放在容器的左邊,不改變它的大小。如果為水平裁剪,那么從右邊開始裁剪(默認) |
right | 將內部的 Drawable 放在容器的右,不改變它的大小。如果為水平裁剪,那么從左邊開始裁剪 |
center_vertical | 將內部的 Drawable 在容器中豎直居中,不改變它的大小。如果為豎直裁剪,那么從上下同時開始裁剪 |
fill_vertical | 使內部的 Drawable 在豎直方向上填充容器,如果為豎直裁剪。那么僅當 ClipDrawable 的等級為 0(0 表示 ClipDrawable 被完全裁剪,既不可見)時,才能有裁剪行為 |
fill_horizontal | 使內部的 Drawable 在水平方向上填充容器,如果為水平裁剪。那么僅當 ClipDrawable 的等級為 0時,才能有裁剪行為 |
center | 使內部的 Drawable 在水平和豎直方向上都居中,不改變它的大小。如果為豎直裁剪,那么從上下同時開始裁剪,如果為水平裁剪,那么從左右同時開始裁剪 |
fill | 使內部的 Drawable 在水平和豎直方向上同時填充容器,僅當 ClipDrawable 的等級為 0時,才能有裁剪行為 |
clip_vertical | 附加選項,表示豎直方向裁剪,較少使用 |
clip_horizontal | 附加選項,表示水平方向裁剪,較少使用 |
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="vertical"
android:drawable="@drawable/image1"
android:gravity="bottom" />
0-10000區間
ClipDrawable drawable = (ClipDrawable) button.getBackground();
drawable.setLevel(8000);
6.3 自定義 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 r = getBounds();
float cx = r.exactCenterX();
float cy = r.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 cf) {
mPaint.setColorFilter(cf);
invalidateSelf();
}
@Override
public int getOpacity() {
// not sure, so be safe
return PixelFormat.TRANSLUCENT;
}
View testCustomDrawable = findViewById(R.id.test_custom_drawable);
CustomDrawable customDrawable = new CustomDrawable(Color.parseColor("#0ac39e"));
testCustomDrawable.setBackgroundDrawable(customDrawable);