領略千變萬化的Android Drawable (一)

轉載請註明出處(萬分感謝!):
http://blog.csdn.net/javazejian/article/details/52247324
出自【zejian的博客

關聯文章:
領略千變萬化的Android Drawable (一)
領略千變萬化的Android Drawable (二)

  Android Drawable 相信大家都不陌生,本篇我們就來全面深入瞭解它,Drawable是一種可以在Canvas上進行繪製的抽象的圖像,它的子類也相當多,所以在開發中很容易導致我們對不同Drawable的理解產生混亂,因此我們很有必要來全面瞭解一下Drawable的子類及其使用方式滴,哈~。

一、Drawable的簡述

  Drawable在我們開發中常被用來作爲View的背景圖像,一般情況下我們都是通過XML來定義Drawable的,當然我們也可以通過代碼創建Drawable,只不過會比較複雜而已。Drawable最大的好處就是可以方便我們做出一些特殊的UI效果,這點比我們自定義View實現的效果來得更容易些。因此深入理解Drawable的用法還是很有必要的,接下來我們來看看Drawable的一些特性:

  • 1、Drawable本身表示的只是一種圖像的概念,因此Drawable不僅僅是圖片,也可以是顏色構造出來的圖像效果(後面會說明)。
  • 2、Drawable本身是一個抽象類,因此具體的實現都是由子類完成的,比如ShapeDrawable,BitmapDrawable等。
  • 3、Drawable的內部寬高可以分別通過getIntrinsicWidth()和getIntrinsicHeight()獲取,但並不是所有的Drawable都有內部寬高的屬性,比如一個顏色形成的Drawable並沒有寬高的概念。在大多數情況下,Drawable並沒有大小的概念,因爲當Drawable作爲View的背景圖時,Drawable會被拉伸至View的同等大小。

二、千變萬化的Drawable

1、BitmapDrawable

  BitmapDrawable 是對bitmap的一種包裝,可以設置它包裝的bitmap在BitmapDrawable區域內的繪製方式,如平鋪填充、拉伸填充或者保持圖片原始大小,也可以在BitmapDrawable區域內部使用gravity指定的對齊方式。其語法如下:

<?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:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] 
     />

我們分析一下這些屬性的含義:
android:src
  類型:Drawable resource。必需。 引用一個drawable resource.
android:antialias
  類型:Boolean。是否開啓抗鋸齒。開啓後圖片會變得更平滑些,因此一般建議開啓,設置爲true即可。
android:dither
  類型:Boolean。是否允許抖動,如果位圖與屏幕的像素配置不同時,開啓這個選項可以讓高質量的圖片在低質量的屏幕上保持較好的顯示效果(例如:一個位圖的像素設置是 ARGB 8888,但屏幕的設置是RGB 565,開啓這個選項可以是圖片不過於失真)一般建議開啓,爲true即可。
android:filter
  類型:Boolean。是否允許對位圖進行濾波。當圖片被壓縮或者拉伸時,使用濾波可以獲得平滑的外觀效果。一般建議開啓,爲true即可
android:gravity
  當圖片小於容器尺寸時,設置此選項可以對圖片經典定位,這個屬性比較多,不同選項可以使用‘|’來組合使用。

可選項 含義
top 將圖片放在容器頂部,不改變圖片大小
bottom 將圖片放在容器底部,不改變圖片大小
left 將圖片放在容器左側,不改變圖片大小
right 將圖片放在容器右側,不改變圖片大小
center_vertical 圖片豎直居中,不改變圖片大小
fill_vertical 圖片豎直方向填充容器
center_horizontal 圖片水平居中,不改變圖片大小
fill_horizontal 圖片水平方向填充容器
center 使圖片在水平方向和豎直方向同時居中,不改變圖片大小
fill 圖片填充容器,默認值
clip_vertical 豎直方向剪切,很少使用
clip_horizontal 水平方向剪切,很少使用

android:mipMap
  紋理映射處理技術,不太懂,不過一般也不用,默認爲false
android:tileMode
  平鋪模式。共有以下幾個值
  disabled :默認值,表示不使用平鋪
  clamp :複製邊緣色彩
  repeat :X、Y 軸進行重複圖片顯示,也就是我們說要說的平鋪
  mirror :在水平和垂直方向上使用交替鏡像的方式重複圖片的繪製
  三者區別如下圖:

  BitmapDrawable的xml使用方式比較簡單,我們這裏就不貼案例了哈。接下來我們來看看在代碼中如何使用BitmapDrawable。

  實際上我們從BitmapDrawable的源碼可以看出,目前Google建議我們創建BitmapDrawable的構造方法有3種

public BitmapDrawable(Resources res, Bitmap bitmap) 

public BitmapDrawable(Resources res, String filepath)

public BitmapDrawable(Resources res, java.io.InputStream is)

  參數比較簡單,res就是我們通過getResource()獲取到的資源管理對象,bitmap就是我們需要用BitmapDrawable包裝的圖片對象,filepath,需要包裝的圖片所在路徑,is則是一個圖像流,需要轉換成 BitmapDrawable。但是在大多數情況下我們還是建議使用xml實現比較好,代碼實現我們不打算深究,我們這裏直接給出一個代碼應用案例:

Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image1);
BitmapDrawable mBitmapDrawable = new BitmapDrawable(getResources(),mBitmap);
mBitmapDrawable.setTileModeXY(TileMode.MIRROR, TileMode.MIRROR);//平鋪方式
mBitmapDrawable.setAntiAlias(true);//抗鋸齒
mBitmapDrawable.setDither(true);//防抖動
//設置到imageView上即可
imageView.setImageDrawable(mBitmapDrawable);

2、NinePatchDrawable

  NinePatchDrawable表示的是我們熟悉的.9格式的圖片,.9圖片可以在保證圖片不失真的情況下任意進行縮放,在實際的使用中我們也是通過Xml來實現即可:

<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"   
    android:src="drawable/resource"  
    android:dither="[true|false]"/>  

  屬性和BitmapDrawable中屬性的含義相同,這裏不過多描述。一般情況下不建議代碼創建.9圖,因爲Android雖然可以使用Java代碼創建NinePatchDrawable,但是極少情況會那麼做,這是因爲由於Android SDK會在編譯工程時對點九圖片進行編譯,形成特殊格式的圖片。使用代碼創建NinePatchDrawable時只能針對編譯過的點九圖片資源,對於沒有編譯過的點九圖片資源都當做BitmapDrawable對待。還有點需要特別注意的是,點九圖只能適用於拉伸的情況,對於壓縮的情況並不適用,如果需要適配很多分辨率的屏幕時需要把點九圖做的小一點。

3、ShapeDrawable

  ShapeDrawable對於Xml的shape標籤,在實際開發中我們經常將其作爲背景圖片使用,因爲ShapeDrawable可以幫助我們通過顏色來構造圖片,也可以構造漸變效果的圖片,總之,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:topLeftRadius="integer"
        android:topRightRadius="integer"
        android:bottomLeftRadius="integer"
        android:bottomRightRadius="integer" />
    <gradient
        android:angle="integer"
        android:centerX="integer"
        android:centerY="integer"
        android:centerColor="integer"
        android:endColor="color"
        android:gradientRadius="integer"
        android:startColor="color"
        android:type=["linear" | "radial" | "sweep"]
        android:usesLevel=["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>

  從代碼中我們可以看出Shape的子元素包括、<gradient>、<padding>、<size>、<solid>、<stroke>,我們一個個分析。
android:shape
  這個屬性表示圖像的形狀,可以是rectangle(矩形)、oval(橢圓)、line(橫線)、ring(圓環)。默認爲rectangle。
這裏對於ring值還有幾個相關的屬性:

屬性 含義
android:innerRadius 圓環的半徑與android:innerRadiusRatio同時存在時,以android:innerRadius 爲準
android:innerRadiusRatio 內半徑佔整個Drawable寬度的比例,默認值爲9.如果爲n,那麼半徑=寬度/n
android:thickness 圓環的厚度,即外半徑減去內半徑的大小與android:thicknessRatio同時存在時以android:thickness爲準
android:thicknessRatio 厚度佔整個Drawable寬度比例,默認值爲3,如果爲n,那麼厚度=寬度/n
android:useLevel 一般都應該使用false,否則可能無法達到預期顯示效果,除非它被當做LevelListDrawable來使用。

<corners>
  指定邊角的半徑,數值越大角越圓,數值越小越趨近於直角,參數爲:

<corners
android:radius="integer"
android:topLeftRadius="integer"
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />

   Android:radius直接指定4個角的半徑,另外4個屬性可以單獨設置4個角的角度.

<gradient>
  設置顏色漸變與<solid>爲互斥標籤,因爲solid表示純色填充,而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
android:type 漸變類別,linear(線性)爲默認值,radial(徑內漸變),sweep(掃描漸變)

  angle=0和angle=90的區別(都爲線性漸變):

  linear(線性)爲默認值,radial(徑內漸變),sweep(掃描漸變)區別如下:

  到這裏我們利用前面的介紹的知識點來實現一個環形進度圈的案例,我們將shape屬性設置爲ring(圓環),然後再設置其內半徑以及環的厚度,並設置漸變色調,shape_drawable.xml代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:innerRadius="20dp"
    android:shape="ring"
    android:thickness="8dp"
    android:useLevel="false" >

    <gradient android:angle="0"
        android:startColor="@color/normal"
        android:centerColor="#5027844F"
        android:endColor="#fff"
        android:useLevel="false"
        android:type="sweep"
        />
</shape>

效果如下:

接着,我們將該自定義環形圈設置給一個旋轉動畫,並利用該旋轉動畫自定義成一個環形進度圈的style,最後將該自定義的style賦值給Progress組件。代碼如下:
自定義旋轉動畫progress_rotate.xml:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/shape_drawable"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="0"
    android:toDegrees="360"
    >
</rotate>

自定義Progress的style:

<style name="CustomProgressStyle" >
    <item name="android:indeterminateDrawable">@drawable/progress_rotate</item>
    <item name="android:minWidth">72dp</item>
    <item name="android:maxWidth">72dp</item>
    <item name="android:minHeight">72dp</item>
    <item name="android:maxHeight">72dp</item>
</style>

應用到Progress組件

<ProgressBar
     android:layout_width="100dp"
     android:layout_height="100dp"
     android:layout_centerInParent="true"
     style="@style/CustomProgressStyle"
     android:indeterminateDuration="700"
     />

效果如下:

<solid>
  表示純色填充,通過android:color設置顏色即可。
<stroke>
描述邊框,屬性如下:

屬性 含義
android:width 描述邊框的寬度,數值越大,越邊框越厚
android:color 邊框的顏色
android:dashWidth 組成虛線的線段寬度
android:dashGap 組成虛線的線段之間的間隔,間隔越大,虛線看起的間隙就越大

  有點要明白的是android:dashWidth和android:dashGap有任意一個爲0,則虛線無法預期顯示。

<padding>
  表示內容或子標籤邊距,4個屬性top、bottom、left、right,需要注意的是這個標籤的作用是爲內容設置與當前應用此shape的View的邊距,而不是設置當前View與父元素的邊距。

<size>
  設置背景大小,width和height倆屬性。一般來說這個值不是shape的最終顯示大小,因爲shape作爲背景時會根據View的大小而填充其背景,因此Shape的大小很多時候是View的大小決定的。
  到這裏,shapeDrawable的基本屬性我們都介紹完了,下面我們來實現一個比較常見的效果,我們在微信朋友圈點贊或者發佈評論時總會出現一個紅色帶數字的小圓圈提示,嗯,我們就來模仿一下這個效果的實現,首先我們必須把shape屬性設置爲oval,並設置其純填充顏色爲紅色,給一個臨時大小寬高大小相同(之所以稱爲臨時大小,是因爲其最終大小由使用的View決定的),這樣一個圓形背景圖就出現啦。代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval"
    >
    <solid android:color="#D90E0E" />
    <size android:height="10dp" android:width="10dp" />
</shape>

  接着應用到我們的TextView屬性中

<TextView
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:textColor="#fff"
    android:text="99"
    android:background="@drawable/shape_circle_number"
    />

  最終效果如下:
  
  實際上在開發中我們經常會利用shapeDrawable來自定義出所需要的各種背景圖像或者顯示圖片,同時也有益於減少對美工圖片的依賴,另外一個好處通過自定義shapeDrawable圖片會比美工圖片的size小很多,這樣我們就能減少不必要的size,以減輕apk的size,可謂兩全其美,因此能用shapeDrawable定義圖像時,應該儘量使用它。

4、LayerDrawable

  一個LayerDrawable是一個可以管理一組drawable對象的drawable。在LayerDrawable的drawable資源按照列表的順序繪製,列表的最後一個drawable繪製在最上層。LayerDrawable對於xml的標籤是<layer-list>其語法如下:

<?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" />
</layer-list>

  一個layer-list可以包含多個item,而每個item則表示一個Drawable。下面我們來說明一下item的一些屬性
android:id
  資源ID,一個爲這個item定義的唯一的資源ID。 使用:”@+id/name”.這樣的方式。可以檢索或修改這個drawable通過下面的方式:View.findViewById() or Activity.findViewById().
android:top
  Integer,Drawable相對於View的頂部的偏移量,單位像素
android:right
  Integer,Drawable相對於View的右邊的偏移量,單位像素
android:bottom
  Integer,Drawable相對於View的底部的偏移量,單位像素
android:left
  Integer,Drawable相對於View的左邊的偏移量,單位像素
android:drawable
  Drawable資源,可以引用已有的drawable資源,也可在item中自定義Drawable。默認情況下,layer-list中的Drawable都會被縮放至View的大小,因此在必要的情況下,我們可以使用android:gravity屬性來控制圖片的展示效果,防止圖片變形或者被過度拉伸。
  下面我們來利用layer-list的疊層效果實現一個文本輸入框的底部橫線背景。

xml 代碼如下:

<?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="@color/colorAccent" />
      </shape>
    </item>

    <item android:bottom="6dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff"/>
        </shape>
    </item>

    <item android:bottom="2dp"
          android:left="2dp"
          android:right="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff" />
        </shape>
    </item>
</layer-list>

  應用到EditText上的代碼:

<EditText                                        
  android:layout_width="200dp"                 
  android:layout_height="wrap_content"         
  android:layout_centerInParent="true"         
  android:background="@drawable/layer_drawable"
  />    

  上面代碼比較簡單,我們就不過的分析,接着我們再利用<layer-list>標籤來實現一個帶陰影的圓角矩形,layer_list_drawable_2.xml代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 灰色陰影 內容距離左邊2dp,距離頂部4dp-->
    <item
        android:left="2dp"
        android:top="4dp">
        <shape>
            <solid android:color="@android:color/darker_gray" />
            <corners android:radius="10dp" />
        </shape>
    </item>
    <!-- 白色前景 內容距離底部4dp 右邊2dp-->
    <item
        android:bottom="4dp"
        android:right="2dp">
        <shape>
            <solid android:color="#FFFFFF" />
            <corners android:radius="10dp" />
        </shape>
    </item>
</layer-list>

  效果如下:
  
當然我們也可以在代碼中實現這裏僅給出示例,不深究,還是建議採用xml的方式定義

Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.image1);
Drawable[] drawables=new Drawable[3];
drawables[0]=new BitmapDrawable(bitmap);
drawables[1]=new BitmapDrawable(bitmap);
drawables[2]=new BitmapDrawable(bitmap);
LayerDrawable layer=new LayerDrawable(drawables);
//設置圖層邊界距離
layer.setLayerInset(0, 20, 20, 0, 0);
layer.setLayerInset(1, 40, 40, 0, 0);
layer.setLayerInset(2, 60, 60, 0, 0);
ImageView imageView=(ImageView)findViewById(R.id.imgView);
imageView.setImageDrawable(layer);

  這樣我們的帶陰影的圓角矩形就出來啦,可以將其作爲其他View的背景使用,美工也就不用提供類似的圖了,到這裏我們應該已經體會帶巧用各種Drawable的威力了。

5、StateListDrawable

  StateListDrawable對於xml的<selector>標籤,這個標籤可以說是我們最常用的標籤了,在開發中,有時候我們需要一個View在點擊前顯示某種狀態,而在點擊後又切換到另外一種狀態,這時我們就需要利用<selector>標籤來實現啦。如下案例,我們在點擊輸入郵件地址前文本框底線是灰色,而在點擊後文本框底線就變成藍色了,這也是<selector>標籤的應用之一。
  
  StateListDrawable本身也是表示Drawable的集合,每個Drawable就對於View的一種狀態,如上面的灰色底線和藍色底線對應着View的兩種V不同時期的狀態,因此我們經常使用StateListDrawable來設置View的背景,以便在不同狀態下顯示不同的效果,從而獲得更優的用戶體驗。其主要語法如下:

<?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"] />
</selector>

item的屬性介紹如下:

屬性 含義
android:drawable 該狀態下要顯示的圖像,可以是Drawable也可以是圖片
android:state_pressed 表示是否處於被按下狀態
android:state_focused 表示是否已得到焦點狀態
android:state_hovered 表示光標是否停留在View的自身大小範圍內的狀態
android:state_selected 表示是否處於被選中狀態
android:state_checkable 表示是否處於可勾選狀態
android:state_checked 表示是否處於已勾選狀態,一般用於CheckBox
android:state_enabled 表示是否處於可用狀態
android:state_active 表示是否處於激活狀態
android:state_window_focused 表示是否窗口已得到焦點狀態

selector標籤的屬性含義如下:
android:constantSize
  StateListDrawable的固有大小是否隨着其狀態改變而改變,因爲在狀態改變後,StateListDrawable會切換到別的Drawable,而不同的Drawable其大小可能不一樣。true表示大小不變,這時其固有大小是內容所有Drawable的固有大小的最大值。false則會隨着狀態改變而改變,默認值爲false
android:variablePadding
  表示 StateListDrawable的padding是否隨狀態的改變而改變,默認值爲false,一般建議設置爲false就行。
android:dither
  是否開啓抖動效果,開啓後可使高質量的圖片在低質量的屏幕上仍然有較好的顯示效果,一般建議開啓,設置爲true。
接下來我們來看一個例子,按鈕點擊前後狀態改變。代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!--獲取焦點狀態-->
    <item
    android:state_focused="true"
    android:drawable="@color/color_state"
    />

    <!--按下狀態-->
    <item android:state_pressed="true"
    android:drawable="@color/color_state" />

    <!--默認狀態下-->
    <item android:drawable="@color/normal" />
</selector>

接着應用到button上:

<Button
       android:padding="8dp"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:text="Selector_State"
       android:textColor="#fff"
       android:background="@drawable/selector_drawable"
       />

效果如下:

  上面是通過顏色定義不同狀態下的顯示 效果,當然我們也可以利用shapeDrawable定義各種背景圖像然後應用到StateListDrawable中,下面我們定義兩個不同狀態下的圓角矩形,並應用到button上
shape_drawable_for_btn_normal.xml代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid android:color="@color/normal"></solid>
    <corners android:radius="8dp" />
</shape>

shape_drawable_for_btn_press.xml代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid android:color="@color/color_state"></solid>
    <corners android:radius="8dp" />
</shape>

selector_for_btn.xml代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!--獲取焦點狀態-->
    <item
        android:state_focused="true"
        android:drawable="@drawable/shape_drawable_for_btn_press"
        />

    <!--按下狀態-->
    <item android:state_pressed="true"
        android:drawable="@drawable/shape_drawable_for_btn_press" />

    <!--默認狀態下-->
    <item android:drawable="@drawable/shape_drawable_for_btn_normal" />
</selector>

應用到button上

<Button
       android:padding="8dp"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerInParent="true"
       android:text="Selector_State"
       android:textColor="#fff"
       android:background="@drawable/selector_for_btn"
       />

最終效果如下:

最後給出一個通過代碼實現的案例給大家參考(建議儘量使用xml定義,代碼定義比較複雜):

/** 設置Selector。 */
    public static StateListDrawable newSelector(Context context, int idNormal, int idPressed, int idFocused,
                                                int idUnable) {
        //相當於<selector>標籤
        StateListDrawable bg = new StateListDrawable();
        Drawable normal = context.getResources().getDrawable(R.drawable.shape_drawable_for_btn_normal);
        Drawable pressed = context.getResources().getDrawable(R.drawable.shape_drawable_for_btn_press);
        Drawable focused =context.getResources().getDrawable(R.drawable.shape_drawable_for_btn_press);
        Drawable unable = context.getResources().getDrawable(R.drawable.shape_drawable_for_btn_unable);
        //設置每種狀態下的Drawable顯示
        // View.PRESSED_ENABLED_STATE_SET
        bg.addState(new int[] { android.R.attr.state_pressed, android.R.attr.state_enabled }, pressed);
        // View.ENABLED_FOCUSED_STATE_SET
        bg.addState(new int[] { android.R.attr.state_enabled, android.R.attr.state_focused }, focused);
        // View.ENABLED_STATE_SET
        bg.addState(new int[] { android.R.attr.state_enabled }, normal);
        // View.FOCUSED_STATE_SET
        bg.addState(new int[] { android.R.attr.state_focused }, focused);
        // View.WINDOW_FOCUSED_STATE_SET
        bg.addState(new int[] { android.R.attr.state_window_focused }, unable);
        // View.EMPTY_STATE_SET
        bg.addState(new int[] {}, normal);
        return bg;
    }

6、LevelListDrawable

  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="@drawable/drawable_resource"
        android:maxLevel="integer"
        android:minLevel="integer" />
</level-list>

屬性說明如下:

屬性 含義
android:drawable 該等級下需要展示的圖片
android:maxLevel 該項所允許的最大level
android:minLevel 該項所允許的最小level

  實際上我們也很容易知道<level-list>標籤中的每個Item各表示一個Drawable,並有與之對應的等級,而等級則是由android:maxLevel和android:minLevel所決定的,其等級範圍是0-10000,最小爲0,默認值,最大則爲10000,還是一樣的做法,先來看一個案例:

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/image4"
        android:maxLevel="0"
        />

    <item android:drawable="@drawable/image1"
          android:maxLevel="1"
        />

    <item android:drawable="@drawable/image2"
        android:maxLevel="2"
        />

    <item android:drawable="@drawable/image3"
        android:maxLevel="3"
        />
</level-list>

  我們定義了4個item,等級分別爲0,1,2,3,它們都有與之對應的Drawable,然後我們在java代碼中實現一個效果,每過2秒更好一個不同等級的圖片,代碼如下:

package com.zejian.drawble;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {
    private static ImageView imageView;

    static Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what==1){
                imageView.getDrawable().setLevel(1);
            }else if(msg.what==2){
                imageView.getDrawable().setLevel(2);
            }else if(msg.what==3){
                imageView.getDrawable().setLevel(3);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView=(ImageView)findViewById(R.id.image);
        imageView.setImageResource(R.drawable.level_list_drawable);
        imageView.setImageLevel(0);

        for (int i=1;i<4;i++){
            handler.sendEmptyMessageDelayed(i,i*2000);
        }
    }
}

實現效果如下:

  實際上我們還可以設置等級範圍,當等級在某個範圍內時去顯示對應範圍內的圖片,這也是可以的。這個比較簡單,這裏就不演示了哈。
  好~,時間不早了,哈~,先休息,剩下的下篇繼續,歡迎繼續關注~~

領略千變萬化的Android Drawable (一)
領略千變萬化的Android Drawable (二)

主要參考資料:
《android開發藝術探索》
《google android官網》

發佈了65 篇原創文章 · 獲贊 3504 · 訪問量 230萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章