本文是學習《Android開發藝術探索》中Drawable章節之后的一個總結。
Drawable在我們平時的開發中,基本都會用到,而且給大家非常的有用。那么什么是Drawable呢?能夠在canvas上繪制的一個玩意,而且相比于View,并不需要去考慮measure、layout,僅僅只要去考慮如何draw(canavs)。當然了,對于Drawable傳統的用法,大家肯定不陌生 ,今天主要給大家帶來以下幾個Drawable的用法:
1、自定義Drawable,相比View來說,Drawable屬于輕量級的、使用也很簡單。以后自定義實現一個效果的時候,可以改變View first的思想,嘗試下Drawable first。
2、自定義狀態,相信大家對于State Drawable都不陌生,但是有沒有嘗試過去自定義一個狀態呢?
3、利用Drawable提升我們的UI Perfermance , 如何利用Drawable去提升我們的UI的性能。
一、常見的Drawable種類介紹
| Drawable類 | xml標簽 | 描述 |
|---|---|---|
| BitmapDrawable | <bitmap/> | 表示一張圖片,與直接引用原始圖片相比可以設置一些效果 |
| ShapeDrawable | <shape/> | 通過顏色構造各種形狀的圖形,標簽對應的實體類實際是GradientDrawable |
| LayerDrawable | <layer-list/> | 表示一種層次化的Drawable集合,可以將不同的Drawable放置在不同的層上達到疊加效果 |
| StateListDrawable | <selector/> | 表示一種Drawable集合,集合中每個Drawable對應著View的一種狀態,最常用于Button |
| LevelListDrawable | <level-list/> | 表示一種Drawable集合,集合中每個Drawable(item)都有一個等級(level)的概念。可以根據不同的等級切換對應的Drawable。每個Drawable(item)對應一個等級范圍,可以通過Drawable的setLevel方法來切換,如果用作ImageView的前景,還可以通過ImageView的setImageLevel方法來切換Drawable。level范圍0-10000。 |
| TransitionDrawable | <transition/> | 用于實現兩個Drawable之間的淡入淡出效果,通過該Drawable中的startTransition和reverseTransition方法實現淡入淡出和逆過程,兩個方法接收一個時間參數。 |
| InsetDrawable | <inset/> | 可以將其他Drawable內嵌到自己當中,并且可以在四周流出一定的距離。當一個View希望背景比自己實際區域小的時候,可以用這個Drawable。LayerDrawable可以實現相同的效果 |
| ScaleDrawable | <scale/> | 可以根據自己的等級將指定的Drawable縮放到一定的比例。 |
| ClipDrawable | <clip/> | 根據自己當前的等級來裁剪另一個Drawable,裁剪方向可以通過android:clipOrientation和android:gravity兩個屬性共同控制。 |
二、各種Drawable的xml屬性詳解
1.<bitmap/>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:src="圖片資源id" android:antialias="true|false" android:dither="true|false" android:filter="true|false" android:gravity="..." android:mipMap="true|false" android:tileMode="disabled|clamp|repeat|mirror" />
antialias抗鋸齒,開啟后會讓圖片變得平滑,同時也會在一定程度上降低圖片的清晰度,但是降低的幅度低至可以忽略,所以應該開啟;
dither抖動效果,當圖片的像素配置與手機屏幕的像素配置不一致時,開啟這個選項可以讓高質量圖片在低質量的屏幕上還能保持較好的顯示效果,比如圖片的色彩模式為ARGB8888,但是設備屏幕所支持的色彩模式為RGB555,這時候開啟抖動選項可以讓圖片顯示不會過于失真,在Android中創建Bitmap一般會選用ARGB8888這個模式,在這種色彩模式下一個像素所占的大小為4個字節,一個像素的位數總和越高,圖像也就越逼真。根據分析,抖動效果應該開啟;
filter過濾效果,當圖片尺寸被拉伸或壓縮時,過濾可以保持較好的顯示效果,應該開啟;
mipMap一種圖像處理技術,不常用,默認false即可;
titleMode平鋪模式。
點9圖片對應NinePatchDrawable,xml標簽是<nine-patch/>
2.<shape/>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle|oval|line|ring"> <corners android:radius="integer" android:topLeftRadius="integer" android:topRightRadius="integer" android:bottomLeftRadius="integer" android:bottomRightRadius="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(圓環)。默認是矩形,line和ring必須通過<stroke>標簽來指定線的寬度和顏色等信息,否則無法達到預期的顯示效果。
針對ring這個形狀,有5個特殊屬性:
android:innerRadius 內環半徑,與android:innerRadiusRatio同時存在時,以android:innerRadius為準
android:thickness 圓環厚度,即外半徑減去內半徑的大小,與android:thicknessRatio同時存在時以android:thickness為準
android:innerRadiusRatio 內半徑占整個Drawable的寬度比例,默認值9。如果是n,那么內半徑=寬度/n
android:thicknessRatio 厚度占整個Drawable的寬度比例,默認值3。如果是n,那么厚度=寬度/n
android:useLevel 一般都應該使用false,否則有可能無法達到預期效果,除非被當作LevelListDrawable來使用
<corners>
表示四個角的角度,只適用于shape,這里的角度指的是圓角的程度,用px來表示,5個屬性:
<gradient>
表示漸變色,與<solid>純色標簽互斥,屬性如下:
<solid>
純色填充,屬性android:color表示填充顏色
<stroke>
Shape的描邊,屬性如下:
<padding>
表示包含它的View的空白,有上下左右四個屬性。
<size>
shape的大小,但不是shape最終的大小因為shape一般會自適應View的寬高。
3.<layer-list/>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="" android:id="" android:top="" android:right="" android:bottom="" android:left="" /></layer-list>
一個layer-list可以包含多個item,每個item表示一個Drawable。
android:top android:right android:bottom android:left設置上下左右的偏移量。
android:drawable 直接引用一個Drawable資源,也可以在item中自定義Drawable。
默認情況layer-list中的所有Drawable都會被縮放至View的大小
4.<selector/>
<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="" 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" /></selector>
android:constantSize屬性表示StateListDrawable的固有大小是否不隨狀態的改變而改變,因為狀態的改變會導致切換到具體的Drawable,而不同狀態的Drawable可能大小不同。true表示固有大小保持不變。dither表示抖動效果。android:variablePadding表示StateListDrawable的padding是否隨狀態的改變而改變,不建議開啟。
<item>
每個item都表示一種狀態下的Drawable信息。常見狀態如下:
android:state_pressed 按下狀態
android:state_focused 獲取焦點
android:state_selected 用戶選擇了View
android:state_checked 用戶選中了View,一般用于CheckBox這類在選中和非選中狀態之間切換的View
android:state_enabled View處于可用狀態
系統會根據View的狀態從selector中選擇對應的item,按照從上到下的順序查找,直至查找到第一個匹配的item。一般默認的item都應該放在selector的最后一條并且不附帶任何狀態,這樣當上面的item都無法匹配View的當前狀態時,就會選擇默認的item,因為默認的item不附帶狀態,所以它可以匹配View的任何狀態。
5.<level-list/>
<level-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="" android:minLevel="" android:maxLevel="" /></level-list>
示例代碼
<?xml version="1.0" encoding="utf-8"?><level-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/s1" android:minLevel="0" android:maxLevel="20"/> <item android:drawable="@drawable/s2" android:minLevel="21" android:maxLevel="40"/> <item android:drawable="@drawable/s3" android:minLevel="41" android:maxLevel="60"/> <item android:drawable="@drawable/s4" android:minLevel="61" android:maxLevel="100"/></level-list>
//id是level_list_img的ImageView用上面的level-list做背景ImageView iv = (ImageView) findViewById(R.id.level_list_img); LevelListDrawable levelListDrawable = (LevelListDrawable) iv.getDrawable();int level = ???; //業務邏輯得出一個level信息,比如當前電量levelListDrawable.setLevel(level); //根據得出的電量level信息顯示level-list中的相應電量的圖片
6.<transition/>
<transition xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="" android:id="" android:left="" android:top="" android:right="" android:bottom="" /></transition>
兩個Drawable之間的淡入淡出效果,屬性同前面的Drawable,示例代碼:
<?xml version="1.0" encoding="utf-8"?><transition xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/drawable1"/> <item android:drawable="@drawable/drawable2"/></transition>
//id是text_view的TextView用上面的transition做背景TextView tv = (TextView) findViewById(R.id.text_view); TransitionDrawable drawable = (TransitionDrawable) tv.getDrawable();drawable.startTransition(1000);//drawable.reverseTransition(1000);//逆過程
7.<inset/>
<inset xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="" android:insetLeft="" android:insetTop="" android:insetRight="" android:insetBottom="" />
將其他drawable內嵌到inset中,并且可以在四周留出一定的間距,屬性和前面的Drawable類似。下面的示例代碼實現了inset中的shape距離View的邊界為15dp,layer-list可以實現相同效果:
<?xml version="1.0" encoding="utf-8"?><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>
8.<scale/>
<scale xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="" android:scaleGravity="" android:scaleHeight="" android:scaleWidth="" />
android:scaleGravity等同于shape中的android:gravity,android:scaleWidth和android:scaleHeight分別表示對指定drawable寬和高的縮放比例,以百分比的形式表示(看下面的示例代碼)。使用scale的時候需要考慮ScaleDrawable的level值,levle是0的時候表示ScaleDrawable不可見,0也是默認值,所以要想ScaleDrawable可見,level等級不能是0。示例代碼如下:
<?xml version="1.0" encoding="utf-8"?><scale xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/test_drawable" android:scaleGravity="center" android:scaleHeight="70%" android:scaleWidth="70%" />
View view = findViewById(R.id.test_view);ScaleDrawable drawable = (ScaleDrawable)view.getBackground();drawable.setLevel(1);
代碼中必須設置level值,否則默認值0是不可見的。level范圍系統內部約定為0-10000,當然設置成20000也能正常工作但不推薦那樣做。
9.<clip/>
<clip xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="" android:clipOrientation="" android:gravity="" />
clipOrientation表示裁剪方向,有水平和豎直兩個方向。gravity和clipOrientation一起才能發揮作用,gravity的值如下:
| 值 | 含義 |
|---|---|
| top | 將內部Drawable放在容器頂部,不改變它的大小。如果豎直裁剪,那么從底部開始裁剪 |
| bottom | 將內部Drawable放在容器底部,不改變它的大小。如果豎直裁剪,那么從頂部開始裁剪 |
| left | 將內部Drawable放在容器左邊,不改變它的大小。如果水平裁剪,那么從右邊開始裁剪 這是默認值 |
| right | 將內部Drawable放在容器右邊,不改變它的大小,如果水平裁剪,那么從左邊開始裁剪 |
| center_vertical | 將內部Drawable在容器中豎直居中,不改變大小,如果豎直裁剪,那么從上下同時開始裁剪 |
| fill_vertical | 將內部Drawable豎直方向填充容器。如果為豎直裁剪,那么僅當ClipDrawable的等級為0時(0表示ClipDrawable被完全裁剪,即不可見),才能有裁剪行為 |
| center_horizontal | 類似center_vertical,方向不同 |
| fill_horizontal | 類似fill_vertical,方向不同 |
| center | 將內部Drawable水平和豎直方向都居中,不改變大小。如果豎直裁剪,那么從上下同時裁剪,如果水平裁剪,那么從左右同時裁剪 |
| fill | 將內部Drawable水平和豎直方向同時填充,僅當ClipDrawable的等級為0時,才有裁剪行為 |
| clip_vertical | 附加選項,表示豎直方向裁剪,較少使用 |
| clip_horizontal | 附加選項,表示水平方向裁剪,較少使用 |
Drawable等級是有范圍的,即0-10000,最小值0表示完全裁剪,即整個Drawable都不可見。最大值10000表示不裁剪。如果豎直方向從上向下裁剪,level值是8000表示裁剪了2000,即在頂部裁剪掉20%的區域,被裁剪的區域就相當于不存在了。
三、Drawable的 level 總結
上面xml屬性介紹中有些drawable中level是很重要的,這里總結一下:
level值的范圍系統規定0-10000,設置level值的方法:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答