Android中常用的Drawable
前言
-
本文的目錄結構
- 前言
- Drawable簡介
- Drawable分類
- BitmapDrawable
- NinePatchDrawable
- ShapeDrawable
- LayerDrawable
- StateListDrawable
- LevelListDrawable
- TransitionDrawable
- InsetDrawable
- ScaleDrawable
- ClipDrawable
- 自定義Drawable </ul> </li> </ul>
-
Drawable表示的是一種可以在Canvas上進行繪制的抽象的概,可以是純顏色,也可以是圖片等。
-
Drawable一般是通過XML來定義,當然也可以通過代碼來創建。
-
Drawable類是抽象類,它是所有Drawable的基類。
-
Drawable的 getIntrinsicWidth() 和 getIntrinsicHeight() 獲取其內部寬/高。并不是所有Drawable都有內部寬/高。圖片所形成的Drawable的內部寬/高就是圖片的寬/高。顏色所形成的Drawable就沒有內部寬/高的概念了。
-
Drawable是沒有大小概念的,當用作View的背景時,會被拉伸至View的同等大小。
-
Drawable的使用范圍很單一:一是作為ImageView中的圖像顯示,二是作為View的背景。
-
對應 <bitmap> 標簽,幾乎是最簡單的Drawable,表示一張圖片。
-
在實際開發中,我們可直接引用原始的圖片,也可通過XML的方式來描述它。
Drawable簡介
Drawable分類
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 :當圖片小于容器的尺寸時,設置此屬性對圖片進行定位。此屬性的可選項較多,也可用 | 來組合使用。
可選項 含義 top 將圖片放在容器的頂部,不改變其大小。 bottom 將圖片放在容器的底部,不改變其大小。 left 將圖片放在容器的左部,不改變其大小。 right 將圖片放在容器的右部,不改變其大小。 center_vertical 使圖片豎直居中,不改變其大小。 center_horizontal 使圖片水平居中,不改變其大小。 fill_vertical 圖片豎直方向填充容器 fill_horizontal 圖片水平方向填充容器 center 使圖片居中,不改變其大小。 fill 圖片填充容器,默認值。 clip_vertical 豎直方向的裁剪。 clip_horizontal 水平方向的裁剪。 -
android:mipMap :是否開啟紋理映射。
-
android:tileMode :平鋪模式。
可選項 含義 disabled 默認值,關閉平鋪模式。 clamp 圖片四周的像素會擴展到周圍區域。 repeat 簡單的水平和豎直方向上的平鋪效果。 mirror 在水平和豎直方向上的鏡面投影效果。 NinePatchDrawable
-
表示一張 .9 格式的圖片。 .9 圖片可自動地根據所需的寬/高進行相應的縮放并保證不失真。
-
在實際使用中直接引用 .9 圖片,也可以通過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 :是否開啟抖動效果。開啟后可讓高質量的圖片在低質量的屏幕上能保持較好的顯示效果。
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(圓環) 。默認是rectangle。注意line和ring必須通過 <stroke> 標簽來指定線的寬度和顏色等信息,否則無法達到預期的顯示效果。
-
android:shape="ring" 有5個特殊屬性。
屬性 描述 android:innerRadius 圓環的內半徑。<Br>會覆蓋android:innerRadiusRatio。 android:innerRadiusRatio 內半徑占整個Drawable寬度的比例。
默認為9,若為n,則內半徑 = 寬度 / n。android:thickness 圓環的厚度。即外半徑減去內半徑的大小。<Br>會覆蓋android:thicknessRatio android:thicknessRatio 厚度占整個Drawable寬度的比例。
默認為3,若為n,則厚度 = 寬度 / n。android:useLevel 常為false,除非它被當做是LevelListDrawable。 -
<corners> :表示shape的四個圓角的角度,只適用于矩形。
- android:radius :為四個角同事設定相同的角度。優先級比以下4個屬性要低。
- android:topLeftRadius :左上角的角度。
- android:topRightRadius :右上角的角度。
- android:bottomLeftRadius :左下角的角度。
- android:bottomRightRadius :右下角的角度。
-
<solid> :純色填充,通過 android:color 指定填充的顏色。
-
<gradient> :漸變效果。與 <solid> 純色填充是互相排斥的。
- android:angle :漸變的角度。默認為0,其值必須為45的倍數。此角度會影響漸變的方向,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 :漸變的類別。有linear(線性漸變)、radial(徑向漸變)、sweep(掃描線漸變),默認為linear。
-
<stroke> :描邊。
- android:width :描邊的寬度。
- android:color :描邊的顏色。
- android:dashWidth :虛線的寬度。
- android:dashGap :虛線之間的間隔。
-
<padding> :空白。有 top 等四個屬性。
-
<size> :大小。其 android:width 和 android:height 分別設定shape的寬/高。注意,這個表示的是shape的固有大小,但并不是其最終大小。
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 中引用一個現有的Drawable資源,也可在 <item> 中自定義Drawable。
-
默認情況下,layer-list中的所有Drawable都會被縮放至View的大小。可設置Drawable相對于View的上下左右偏移量。另外對于bitmap,需要使用其 android:gravity 來控制圖片的顯示效果。
-
layer-list有層次的概念, 下面的item會覆蓋上面的item 。通過合理的分層,可實現一些特殊的疊加效果。
-
利用layer-list實現一個文本輸入框。
<?xml version="1.0" encoding="utf-8"?> <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>
layer-list背景的輸入框
StateListDrawable
- 對應 <selector> 標簽,表示一個Drawable的集合。 每個Drawable對應著View的一種狀態 ,系統會根據View的狀態來選擇合適的Drawable。
<?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的固有大小是否不隨著其狀態的改變而改變。默認為false,即隨著狀態的改變而改變大小。若為true,則表示其內部所有Drawable的固有大小的最大值。
-
android:dither :是否開啟抖動效果。
-
android:variblePadding :StateListDrawable的padding是否隨著其狀態的改變而改變。默認為false,表示其內部所有Drawable的padding的最大值。若為true,表示會隨著狀態的改變而改變。
-
<item> :表示某種狀態下的一個具體的Drawable。用 android:drawable 指定一個現有Drawable的資源id,剩下的屬性表示的是View的各種狀態。
狀態 含義 android:state_pressed 表示按下狀態。 android:state_focused 表示已經獲取了焦點。 android:state_selected 表示用戶選擇了View。 android:state_checked 表示用戶選中了View。<Br>適用于CheckBox這類在選中和非選中狀態之間進行切換的View。 android:state_enabled 表示View當前處于可用狀態。 - 系統會按照從上到下的順序查找,直至查找到第一條匹配的item。一般來說,默認的item都應該放在selector的最后一條,并且不附帶任何的狀態。
LevelListDrawable
- 對應 <level-list> 標簽,表示一個Drawable集合,集合中的每個Drawable都有一個等級的概念。根據不同的等級,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>
-
每個item表示一個Drawable,并且有對應的等級范圍,在 maxLevel 和 minLevel 之間。取值范圍為0~10000,默認為0。
-
若作為View背景時,可通過Drawable的 setLevel() 來設置不同的等級來切換具體的Drawable。若作為ImageView的前景,可通過ImageView的 setImageLevel() 來切換。
TransitionDrawable
- 對應于 <transition> 標簽,用于實現兩個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() 來實現淡入淡出效果以及它的逆過程。
ImageView ivBg = (ImageView) findViewById(R.id.iv_bg); TransitionDrawable drawable = (TransitionDrawable) ivBg.getBackground(); drawable.startTransition(1000);
InsetDrawable
- 對應 <inset> 標簽,可將其他Drawable內嵌到自己當中,并可在四周留出一定的間距。
<?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" />
- 當一個View希望自己的背景比自己的實際區域小的時候,可采用InsetDrawable,并通過 inset* 屬性來設置留白。
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" />
-
android:scaleGravity :等同于BitmapDrawable的 android:gravity 。
-
android:scaleWidth 和 android:scaleHeight :指定Drawable寬/高的縮放比例,以百分比的形式表示。如 70% ,表示縮放到原來的30%。
- 從ScaleDrawable的 draw() 源代碼來看,若等級為0時,不可見。等級默認為0,所以調用ScaleDrawable的 setLevel() 設置一個大于0的等級,它才會可見。
public void draw(Canvas canvas) { final Drawable d = getDrawable(); if (d != null && d.getLevel() != 0) { d.draw(canvas); } }
- 分析ScaleDrawable的 onBoundsChange() 可看出 其內部mDrawable的大小和等級以及縮放比例的關系 。
// iw常為0 final int iw = min ? d.getIntrinsicWidth() : 0; // 1. MAX_LEVEL為10000,即等級的取值范圍為0~10000。 // 2. 計算得到的最終w為其內部mDrawable最后顯示的寬度。因為是-=,所以右邊算數得到的值越大,則最終w就越小。 // 3. level越大,其內部mDrawable就越大。 // 4. ScaleDrawable的XML中所定義的縮放比例越大,即mState.mScaleWidth越大,則內部mDrawable就越小。 w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
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 一起發揮作用。它的取值有下表各種選項,可用 | 來組合使用。
選項 含義 top 放在容器的頂部,不改變大小。
若為豎直裁剪,則從底部開始裁剪。bottom 放在容器的底部,不改變大小。
若為豎直裁剪,則從頂部開始裁剪。left 這是默認值。放在容器的左邊,不改變大小。
若為水平裁剪,則從右邊開始裁剪。right 放在容器的右邊,不改變大小。
若為水平裁剪,則從左邊開始裁剪。center_vertical 在容器中豎直居中,不改變大小。
若為豎直裁剪,則從上下同時裁剪。center_horizontal 在容器中水平居中,不改變大小。
若為水平裁剪,則從左右同時裁剪。center 居中,不改變大小。
若為豎直裁剪,則從上下同時裁剪。
若為水平裁剪,則從左右同時裁剪。fill_vertical 在豎直方向上填充容器。
若為豎直裁剪,僅當等級為0時才能有裁剪行為。fill_horizontal 在水平方向上填充容器。
若為水平裁剪,僅當等級為0時才能有裁剪行為。fill 完全填充容器。
僅當等級為0時才能有裁剪行為。clip_vertical 附加選項,表示豎直方向的裁剪。較少使用。 clip_horizontal 附加選項,表示水平方向的裁剪。較少使用。 - ClipDrawable的裁剪程度由level控制,調用 setLevel() 可修改此值。其取值范圍為0~10000。0表示完全裁剪,即整個Drawable都不可見;而10000表示不裁剪。也 可將level理解為可見區域大小,0表示可見區最小,10000表示可見區最大。
自定義Drawable
-
Drawable的工作原理很簡單,其核心就是 draw() 。系統會調用Drawable的 draw() 來繪制View的背景或ImageView的圖像,于是我們可通過重寫其 draw() 來實現自定義Drawable。
-
通常我們沒有必要去自定義Drawable,因為無法在XML中使用自定義Drawable,這就降低了其使用范圍。
-
創建自定義Drawable,必須重寫其 draw() 、 setAlpha() 、 setColorFilter() 、 getOpacity() 等方法。以下為自定義Drawable示例:
/**
- 自定義Drawable
Created by daking on 16/9/15. */ 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;
} }</code></pre>
CustomDrawable drawable = new CustomDrawable(Color.BLUE); imageView.setBackgroundDrawable(drawable);
-
若自定義的Drawable有固有大小時,要重寫 getIntrinsicWidth() 和 getIntrinsicHeight() 。因為這兩個方法會影響到View的 wrap_content 布局。
-
注意,Drawable的內部大小不等于Drawable的實際區域大小。可通過 getBounds() 獲得Drawable的實際區域大小,一般與它的View尺寸相同。
來自:http://www.jianshu.com/p/fd358b03b64c
-