天天看點

Android各種Drawable基礎講解以及使用執行個體

轉載自  :

https://blog.csdn.net/linghu_java/article/details/42119969

       Android把可繪制的對象抽象為Drawable,不同的圖形圖像資源就代表着不同的drawable類型。Android FrameWork提供了一些具體的Drawable實作,通常在代碼中都不會直接接觸Drawable的實作類。

        在實際的開發過程中,會把使用到的資源都放置在res/drawable目錄,剩下的工作交給Android SDK 就行了,當需要使用圖檔資源的時候,可以使用@drawable标志在xml中引用drawable資源就行,也可以在代碼中使用id引用這些drawable資源.

        在使用drawable資源的時,有一點需要注意,drawable預設是記憶體共享的,也就說在不同的地方使用了同一個drawable,它們都指向相同的資源,而且具有相同的狀态,如果在一個地方修改了這個drawable,所有使用它的地方都會改變。

        Android内置了如下幾種Drawable類型:ColorDrawable、GradientDrawable、BitmapDrawable、 NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、RotateDrawable、AnimationDrawable、LayerDrawable、LevelListDrawable、StateListDrawable、TransitionDrawable.

       除了這些預置的drawable實作類以外,也可以自定義drawable的實作類型,大部分情況都不需要自定義drawable類型,使用系統提供的這些drawable實作類型已經覆寫了很多情況。在實際的程式設計過程中也很少會接觸這些具體drawable實作類型,因為編寫android應用程式使用xml可以很容易的建立drawable,隻有在程式中需要修改drawable的屬性時,才需要使用具體的drawable類型提供的方法來處理。下面就來逐個認識這些Drawable類型。

一、ColorDrawable

        ColorDrawable 是最簡單的Drawable,它實際上是代表了單色可繪制區域,它包裝了一種固定的顔色,當ColorDrawable被繪制到畫布的時候會使用顔色填充Paint,在畫布上繪制一塊單色的區域。

        在xml檔案中使用color作為根節點來建立ColorDrawable,它隻有一個android:color屬性,通過它來決定ColorDrawable的顔色,Android并沒有提供修改這個顔色值的Api,是以這個顔色一旦設定之後,就不能直接修改了。

 下面的xml檔案定義了一個顔色為紅色的ColorDrawable:

[代碼]xml代碼:

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

        當然也可以使用Java代碼建立ColorDrawable,需要注意的是Android中使用一個int類型的資料表示顔色值,通常習慣使用十六進制格式的資料表示顔色值。一個int類型包含四個位元組,分别代表顔色的4個組成部分:透明度(Alpha)、紅(RED)、綠(GREEN)、藍(BLUE),每個部分由一個位元組(8個bit)表示,取值範圍為0~255。在xml中使用顔色時可以省略透明度(Alpha)部分,如#ff0000表示紅色。但是在代碼中必須要明确指出透明度(Alpha)代表的資料,如果省略了就表示完全透明的顔色,例如0xFFFF0000表示紅色,而0xFF0000雖然也表示紅色,但它卻是完全透明的,也就是說當繪制到畫布上時,看不出有任何效果.

        使用Java代碼也可以建立ColorDrawable,代碼如下:

[代碼]java代碼:

ColorDrawable drawable = 

new

ColorDrawable(

0xffff0000

);

二、GradientDrawable

GradientDrawable 表示一個漸變區域,可以實作線性漸變、發散漸變和平鋪漸變效果,在Android中可以使用GradientDrawable表示很多複雜而又絢麗的界面效果。

    可以使用xml定義GradientDrawable,相對于ColorDrawable類型,GradientDrawable要複雜很多,它有很多的元素組成。在xml檔案中使用shape作為根節點來建立GradientDrawable,它包含很多屬性和子節點,下面是GradientDrawable的xml文檔節點結構。

[代碼]xml代碼:

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

    <size/>// 定義區域的大小
    
    <gradient/>//設定區域背景的漸變效果

    <solid/> //設定區域的背景顔色,如果設定了solid會覆寫gradient的效果

    <stroke/> //設定區域的邊框效果

    <padding/> //設定區域的内邊距

</shape>
           

在我們實際操作shape的時候我們需要先了解shape的各種屬性的作用:

<?xml version="1.0" encoding="utf-8"?>

<shape

    xmlns:android="http://schemas.android.com/apk/res/android"

    android:shape=["rectangle" | "oval" | "line" | "ring"]      //共有4種類型,矩形(預設)/橢圓形/直線形/環形

    // 以下4個屬性隻有當類型為環形時才有效

    android:innerRadius="dimension"     //内環半徑

    android:innerRadiusRatio="float"    //内環半徑相對于環的寬度的比例,比如環的寬度為50,比例為2.5,那麼内環半徑為20

    android:thickness="dimension"   //環的厚度

    android:thicknessRatio="float"     //環的厚度相對于環的寬度的比例

    android:useLevel="boolean">    //如果當做是LevelListDrawable使用時值為true,否則為false.

    <corners    //定義圓角

        android:radius="dimension"      //全部的圓角半徑

        android:topLeftRadius="dimension"   //左上角的圓角半徑

        android:topRightRadius="dimension"  //右上角的圓角半徑

        android:bottomLeftRadius="dimension"    //左下角的圓角半徑

        android:bottomRightRadius="dimension" />    //右下角的圓角半徑

    <gradient   //定義漸變效果

        android:type=["linear" | "radial" | "sweep"]    //共有3中漸變類型,線性漸變(預設)/放射漸變/掃描式漸變

        android:angle="integer"     //漸變角度,必須為45的倍數,0為從左到右,90為從上到下

        android:centerX="float"     //漸變中心X的相當位置,範圍為0~1

        android:centerY="float"     //漸變中心Y的相當位置,範圍為0~1

        android:startColor="color"      //漸變開始點的顔色

        android:centerColor="color"     //漸變中間點的顔色,在開始與結束點之間

        android:endColor="color"    //漸變結束點的顔色

        android:gradientRadius="float"  //漸變的半徑,隻有當漸變類型為radial時才能使用

        android:useLevel=["true" | "false"] />  //使用LevelListDrawable時就要設定為true。設為false時才有漸變效果

    <padding    //内部邊距

        android:left="dimension"

        android:top="dimension"

        android:right="dimension"

        android:bottom="dimension" />

    <size   //自定義的圖形大小

        android:width="dimension"

        android:height="dimension" />

    <solid  //内部填充顔色

        android:color="color" />

    <stroke     //描邊

        android:width="dimension"   //描邊的寬度

        android:color="color"   //描邊的顔色

        // 以下兩個屬性設定虛線

        android:dashWidth="dimension"   //虛線的寬度,值為0時是實線

        android:dashGap="dimension" />      //虛線的間隔

</shape>

以下是幾種不同漸變效果實作的xml檔案代碼:

<?xml version="1.0" encoding="utf-8"?>
<!--線性漸變的橢圓-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <gradient
        android:type="linear"
        android:angle="90"
        android:gradientRadius="200dp"
        android:startColor="#e61010"
        android:centerColor="#38df0e"
        android:endColor="#d7da08"/>
    <stroke
        android:color="#ffffff"
        android:width="3dp"
        android:dashGap="5dp"
        android:dashWidth="5dp"/>
</shape>
           
Android各種Drawable基礎講解以及使用執行個體
<?xml version="1.0" encoding="utf-8"?>
<!--平鋪漸變的圓環-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="ring"
    android:innerRadiusRatio="8"
    android:thicknessRatio="3"
    android:useLevel="false"
    >
    <gradient
        android:type="sweep"
        android:useLevel="false"
        android:gradientRadius="200dp"
        android:startColor="#e61010"
        android:centerColor="#38df0e"
        android:endColor="#d7da08"/>
</shape>
           
Android各種Drawable基礎講解以及使用執行個體
<?xml version="1.0" encoding="utf-8"?>
<!--發散漸變效果的圓-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="ring"
    android:innerRadius="0dp"
    android:thickness="70dp"
    android:useLevel="false"
    >
    <gradient
        android:type="radial"
        android:useLevel="false"
        android:gradientRadius="50dp"
        android:startColor="#e61010"
        android:centerColor="#38df0e"
        android:endColor="#d7da08"/>
</shape>
           
Android各種Drawable基礎講解以及使用執行個體

三、BitmapDrawable

   BitmapDrawable 是對bitmap的一種包裝,可以設定它包裝的bitmap在BitmapDrawable區域内的繪制方式,如平鋪填充、拉伸填充或者保持圖檔原始大小,也可以在BitmapDrawable區域内部使用gravity指定的對齊方式。

在xml檔案中使用bitmap作為根節點來定義BitmapDrawable。

 下面的xml代碼定義一個BitmapDrawable,同時設定了BitmapDrawable的tileMode 屬性為repeat,通過這樣設定會使用小圖檔在水準和豎直方向做鏡面平鋪效果。

[代碼]xml代碼

<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_person"
    android:antialias="true"
    android:dither="true"
    android:filter="true"
    android:mipMap="false"
    android:gravity="center"
    android:tileMode="repeat">
</bitmap>
           

原圖:

Android各種Drawable基礎講解以及使用執行個體

效果圖:

Android各種Drawable基礎講解以及使用執行個體

Bitmap的屬性:

Android各種Drawable基礎講解以及使用執行個體

gravity屬性詳情:

Android各種Drawable基礎講解以及使用執行個體

  也可以使用Java代碼實作相同的效果,等價的Java代碼如下:

Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_person);

BitmapDrawable mBitmapDrawable = new BitmapDrawable(mBitmap);

mBitmapDrawable.setTileModeXY(TileMode.MIRROR, TileMode.MIRROR);

mBitmapDrawable.setAntiAlias(true);

mBitmapDrawable.setDither(true);

mDrawable = mBitmapDrawable;

四、NinePatchDrawable (點九圖)

NinePatchDrawable,“點九圖”是Andriod平台的一種特殊的圖檔格式,檔案擴充名為:.9.png。支援Android平台的手機類型很多,有多種不同的分辨率,很多控件的切圖檔案在被放大拉伸後,邊角會模糊失真。在android平台下使用“點九”圖檔處理技術,可以将圖檔橫向和縱向同時進行拉伸,以實作在多分辨率下的完美顯示效果。點九圖檔在拉伸時仍能保留圖像的漸變質感和圓角的精細度。

 Android SDK工具集提供了處理點九圖檔的工具,可以通過draw9patch.bat運作,通過這個工具可以很容易把普通的PNG圖檔處理成“點九”圖檔。從它的名字也很容易了解“點九”圖的含義,其實相當于把一張PNG圖分成了9個部分(九宮格),分别為4個角,4條邊,以及一個中間區域,4個角是不做拉伸的,是以還能一直保持圓角的清晰狀态,而2條水準邊和2條垂直邊分别隻做水準和垂直拉伸,是以不會出現邊框被拉粗的情況,隻有中間用黑線指定的區域做拉伸,通過這種處理方式圖檔才不會失真。

自己生成 .9圖:ic_launcher.9.png

Android各種Drawable基礎講解以及使用執行個體

 使用了*.9.png圖檔技術後,隻需要采用一套界面切圖去适配不同的分辨率,而且大幅減少安裝包的大小。Android FrameWork在顯示點九圖檔時使用了高效的優化算法,所示應用程式不需要專門做處理就可以實作圖檔拉伸自适應,減少了代碼量和實際開發的工作量。 

  在xml檔案中使用使用nine-patch作為根節點建立NinePatchDrawable。同時,也可以使用bitmap包裝點九圖檔,android FrameWork會根據android:src屬性設定的圖檔類型來生成對應的drawable。代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<nine-patch
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_launcher"
    android:dither="true">
</nine-patch>
           

 下面看一下原始點九圖檔以及拉伸之後的效果:

Android各種Drawable基礎講解以及使用執行個體

        最後,需要指出的是,Android雖然可以使用Java代碼建立NinePatchDrawable,但是極少情況會那麼做,主要的原因是由于Android SDK會在編譯工程時對點九圖檔進行編譯,形成特殊格式的圖檔。使用代碼建立NinePatchDrawable時隻能針對編譯過的點九圖檔資源,對于沒有編譯過的點九圖檔資源都當做BitmapDrawable對待。在使用點九圖檔時需要注意的是,點九圖隻能适用于拉伸的情況,對于壓縮的情況并不适用,如果需要适配很多分辨率的螢幕時需要把點九圖做的小一點。

五、InsetDrawable

InsetDrawable 表示一個drawable嵌入到另外一個drawable内部,并且在内部留一些間距,這一點很像drawable的padding屬性,差別在于 padding表示drawable的内容與drawable本身的邊距,insetDrawable表示兩個drawable和容器之間的邊距。當控件需要的背景比實際的邊框小的時候比較适合使用InsetDrawable。

總結一下:

  1. 對應

    inset

    标簽
  2. 将其他Drawable内嵌到自身,并在四周留出間距
  3. View需要背景比自己實際區域要小的時候,可以使用

    inset

    layer-list

    也可以實作該需求

下面的xml定義了一個四邊邊距都為20dip的InsetDrawable,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/icon_fengjng"
    android:insetLeft="20dp"
    android:insetRight="20dp"
    android:insetTop="20dp"
    android:insetBottom="20dp">

</inset>
           

效果圖:上邊是引入insetdrawable,下邊是原圖:空白部分可以看出效果

<Button
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/inset_drawable"
    android:text="button"/>
<Button
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/icon_fengjng"
    android:text="button"/>
           
Android各種Drawable基礎講解以及使用執行個體

六、ClipDrawable

ClipDrawable 是對一個Drawable進行剪切操作,可以控制這個drawable的剪切區域,以及相相對于容器的對齊方式,android中的進度條就是使用一個ClipDrawable實作效果的,它根據level的屬性值,決定剪切區域的大小。

在xml檔案中使用clip作為根節點定義ClipDrawable。

需要注意的是ClipDrawable是根據level的大小控制圖檔剪切操作的,官方文檔的note中提到:The drawable is clipped completely and not visible when the level is 0 and fully revealed when the level is 10,000。也就是level的大小從0到10000,level為0時完全不顯示,為10000時完全顯示。是用Drawable提供的setLevel(int level)方法來設定剪切區域。

方向:android:clipOrientation="vertical|horizontal"

          android:gravity="left|right|top|bottom|center"

xml代碼:

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/icon_fengjng"
    android:clipOrientation="vertical"
    android:gravity="center">

</clip>
           

在MainActviity中用一個seekBar來控制ClipDrawable的level,調用的是它的setLevel()方法。最終可以讓它顯示不同的比例。

xml代碼:

<ImageView
    android:id="@+id/iv_clip"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_marginTop="20dp"
    android:src="@drawable/clip_drawable"/>
<SeekBar
    android:id="@+id/seekbar"
    android:layout_marginTop="10dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
           

然後是Activity檔案中:

ivClip = (ImageView) findViewById(R.id.iv_clip);
seekBar = (SeekBar) findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        int max = seekBar.getMax();
        double scale =(double) progress /(double) max;
        ClipDrawable drawable =(ClipDrawable) ivClip.getDrawable();
        drawable.setLevel((int) (10000*scale));
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }
});
           

最終效果圖:

沒辦法錄制gif圖,看看别人的效果圖吧:https://blog.csdn.net/briblue/article/details/53528837

七、ScaleDrawable

ScaleDrawable是對一個Drawable進行縮放操作,ScaleDrawable與ClipDrawable類似,可以根據設定的level值對drawable進行縮放,但與ClipDrawable不同的是,ScaleDrawable還可以根據設定

android:scaleWidth

android:scaleHeight

進行相應百分比的縮放。

在xml檔案中使用scale作為根節點來建立RotateDrawable。

元素: 

<scale>

定義一個ScaleDrawable,必須作為根元素。

  • android:drawable Drawable 資源。必須的。引用一個drawable資源。
  • android:scaleHeight 縮放的高度,以百分比的方式表示drawable的縮放。形式例如:100%,12.5%。
  • android:scaleWidth 縮放的寬度,以百分比的方式表示drawable的縮放。形式例如:100%,12.5%。
  • android:scaleGravity 指定縮放後的gravity的位置。必須是下面的一個或多個值(多個值之間用”|”分隔) 
    • top 将這個對象放在容器的頂部,不改變其大小。
    • bottom 将這個對象放在容器的底部,不改變其大小。
    • left 将這個對象放在容器的左部,不改變其大小。預設值。
    • right 将這個對象放在容器的右部,不改變其大小。
    • center_vertical 将對象放在垂直中間,不改變其大小。
    • fill_vertical 如果需要的話,該對象的垂直尺寸将增加,以便完全填充它的容器。
    • center_horizontal 将對象放在水準中間,不改變其大小。
    • fill_horizontal 如果需要的話,該對象的水準尺寸将增加,以便完全填充它的容器。
    • center 将對象放置在其容器的中心和水準軸的中心位置,而不改變它的大小。
    • fill 如果需要的話,該對象的水準和垂直方向的大小将增加,使得完全填充它的容器。
    • clip_vertical 可以設定為在其容器邊界上的頂部和/或底部邊緣的附加選項。該剪輯是基于垂直gravity:一個頂部gravity剪輯的底部邊緣,底部重力剪輯的頂部邊緣,既不剪輯兩個邊。
    • clip_horizontal 與clip_vertical類似,隻是剪輯是基于水準gravity。

drawable:xml代碼:(縮放各設為50%)

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/icon_fengjng"
    android:scaleGravity="left"
    android:scaleHeight="50%"
    android:scaleWidth="50%">
</scale>
           

然後在layout中使用:

<ImageView
    android:id="@+id/iv_scale"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:src="@drawable/scale_drawable"/>
           

但是如果我們直接運作,發現并沒有顯示圖檔,檢視ScaleDrawable的源碼,發現draw()方法有判斷

getLevel() != 0

才繪制。而我們在沒有

setLevel()

時,預設

getLevel()

都是0。

是以如果我們想正常顯示圖檔,還需要設定drawable的level。如下:

ivScale = (ImageView) findViewById(R.id.iv_scale);
ScaleDrawable drawable = (ScaleDrawable) ivScale.getDrawable();
drawable.setLevel(1);
           

ScaleDrawable的

level

為0,不可見。為10000時,不縮放。我們一般設定level為1,這樣,圖檔就會根據xml中的android:scaleWidth和android:scaleHeight進行相應的縮放了。例如我們設定長寬縮放比例為50%,那麼圖檔長和寬都是原來的一倍,圖檔大小實際是原來大小的四分之一。 

效果如下:

Android各種Drawable基礎講解以及使用執行個體

上面是設定縮放之後的,下面是原圖,圖檔變為原來的1/4.

八、 RotateDrawable

  RotateDrawable 是對一個Drawable進行旋轉操作,可以根據level屬性控制這個drawable旋轉角度,也可以設定相對于它所在容器的對齊方式。

在xml檔案中使用rotate作為根節點來定義RotateDrawable.

Android各種Drawable基礎講解以及使用執行個體

drawable下-xml代碼:

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

    <!-- android:drawable ===Drawable 資源。必須的。引用一個drawable資源。-->
    <!--android:fromDegrees == 整形。  從多少的角度開始旋轉-->
    <!--android:toDegrees == 整形。  到多少的角度結束旋轉-->
    <!--android:pivotX == 百分比。  旋轉的中心在圖檔X軸的百分比-->
    <!--android:pivotY == 百分比。  旋轉的中心在圖檔Y軸的百分比-->
    <!--android:visible == Boolean。是否可見。-->
</rotate>
           

這裡的pivotY、pivotX分别代表旋轉中心的位置,50%代表drawable的中心為旋轉中心。toDegrees代表最大可以旋轉的角度。在代碼中是通過level值确定的,這兩個值之間存在對應關系。如果設定最大旋轉角度為180,那麼Level=10000代表的就是旋轉180度,5000代表旋轉90度,如果最大旋轉角度設定為270度,那麼level=5000,就代表要旋轉135度。可以自己嘗試一下!!!(都是順時針旋轉)。

借鑒:https://blog.csdn.net/u011043551/article/details/61619282

layout使用 裡xml代碼:

<ImageView
    android:id="@+id/iv_rotate"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_marginTop="20dp"
    android:scaleType="fitXY"
    android:background="@color/colorAccent"
    android:src="@drawable/rotate_drawable"/>
           

在這裡我将ImageView的背景設定為紅色,drawable設定為圖檔顯示來源,通過執行個體你就會發現,旋轉的并不是imageView,僅僅隻是drawable旋轉了,然後再将旋轉後的drawable重新輸入到ImageView中。有背景色對比顯得更清楚。。。

acticity裡代碼:

private boolean isRotating = false;
private static final int update_rotate = 100;
private RotateDrawable rotateDrawable;

private Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case update_rotate:
                int level = rotateDrawable.getLevel();
                if(level >= 10000){
                    timer.cancel();
                    rotateDrawable.setLevel(0);
                } else {
                    rotateDrawable.setLevel(level +100);
                }
                break;
        }
    }
};
           
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_drawable);
    
    ivRotate = (ImageView) findViewById(R.id.iv_rotate);
    rotateDrawable = (RotateDrawable) ivRotate.getDrawable();
    rotateDrawable.setLevel(0);

    ivRotate.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            isRotating = true;
            if(isRotating){
                timer.start();
            }
        }
    });
}
           

定時器:

private CountDownTimer timer = new CountDownTimer(Integer.MAX_VALUE,60) {
    @Override
    public void onTick(long millisUntilFinished) {
        mHandler.sendEmptyMessage(update_rotate);
    }

    @Override
    public void onFinish() {
        isRotating = false;
    }
};
           

通過點選圖檔,開啟定時器:在代碼中通過定時器和handler實作UI重新整理。

效果圖借鑒:

Android各種Drawable基礎講解以及使用執行個體

九、AnimationDrawable

AnimationDrawable 對應于Android中的幀動畫,就是把一系列的drawable按照一定的順序,一幀一幀的播放,并且可以使用android:oneshot屬性設定是否循環播放。

android:oneshot

 清單屬性設定為true,它将循環一次,然後停止并保持最後一幀。如果它設定為false,則動畫将循環。

在xml檔案中使用animation-list作為根節點定義AnimationDrawable,使用item設定需要播放的每一幀使用的drawable資源,以及每一幀持續的時常。

下面定義一個包含五幀的AnimationDrawable,循環播放,幀間隔為300毫秒,代碼如下

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/icon_fengjng1"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng2"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng3"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng4"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng5"
        android:duration="300"/>
</animation-list>
           

layout使用:

<ImageView
    android:id="@+id/iv_anim"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:src="@drawable/anim_drawable"/>
           

activity調用AnimationDrawable的 .start() 播放動畫:

ivAnim = (ImageView) findViewById(R.id.iv_anim);
animDrawable = (AnimationDrawable) ivAnim.getDrawable();
animDrawable.start();
           

需要注意的是,當我們在Activity的oncreate方法中調用start方法時會沒有任何效果,那是因為view還沒有初始化完成,無法播放動畫,是以需要使用handler來延遲播放動畫,具體實作代碼如下:

ivAnim = (ImageView) findViewById(R.id.iv_anim);
animDrawable = (AnimationDrawable) ivAnim.getDrawable();
//使用Handler
Handler animHandler = new Handler();
//調用PostDelay()方法去執行,最後的300表示每隔300重新循環執行一次,可以了解成定時器
animHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        animDrawable.start();

    }
},1000);
           

效果借鑒别人圖檔:

Android各種Drawable基礎講解以及使用執行個體

十、LayerDrawable

LayerDrawable 管理一組drawable,每個drawable都處于不同的層,當它們被繪制的時候,按照順序全部都繪制到畫布上。雖然這些drawable會有交差或者重疊的區域,但是它們是位于不同的層,彼此之間不會影響。

在xml檔案中使用layer-list作為根節點來定義LayerDrawable,通過item子節點定義每一層的drawable,layer-list沒有屬性節點,隻包含item子節點。它表示一種階層化的Drawable集合,通過将不同的Drawable放置在不同的層上面達到一種疊加的效果。

其中 可以包含多個

item

,每個item表示一個Drawable

        item中可以通過

android:drawable

直接引用資源,如:

<

item

android:drawable

=

"@drawable/layer1"

/>

   android:top

等表示Drawable相當于View上下左右的偏移量

drawable下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="#fff"/>
            </shape>
        </item>

        <item
            android:bottom="1dp"
            android:left="1dp"
            android:right="1dp">
            <shape android:shape="rectangle">
                <solid android:color="#fff"/>
            </shape>

        </item>

</layer-list>
           

使用:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="15dp"
    android:hint="請輸入文字"
    android:background="@drawable/layer_drawable"/>
           

效果圖:

Android各種Drawable基礎講解以及使用執行個體

十一、LevelListDrawable

對應于level-list标簽

擁有多個item,每個item都有maxLevel和minLevel

Level的範圍為0~10000

給定level後,會按從上至下的順序比對,直到找到範圍合适的Drawable,并傳回

item的level一定要降序或者升序

調用View的getBackground獲得Drawable對象,并調用setLevel設定等級level

ImageView的setImageLevel()能快速指定src引用的Drawable的Level

LevelListDrawable是根據level改變,選擇不同的Drawable,能用于實作進度條、音量調節等等

LevelListDrawable的使用:

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

layout布局:

<Button
    android:id="@+id/btn_fengjing"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:text="風景"/>
<Button
    android:id="@+id/btn_person"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:text="人物"
    />
<ImageView
    android:id="@+id/iv_level"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:src="@drawable/level_drawable"
    />
           

activity使用:

btnScenery = (Button) findViewById(R.id.btn_fengjing);
    btnPerson = (Button) findViewById(R.id.btn_person);
    ivLevel = (ImageView) findViewById(R.id.iv_level);
    ivAnim.setImageLevel(50);
    btnScenery.setOnClickListener(this);
    btnPerson.setOnClickListener(this);

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.btn_fengjing:
            ivLevel.setImageLevel(50);
            break;
        case R.id.btn_person:
            ivLevel.setImageLevel(150);
            break;
    }

}
           

效果圖:預設風景圖,點選後變為人物,再次點選風景按鈕,又變回風景,ImageView根據level值來查找顯示哪張圖檔:

Android各種Drawable基礎講解以及使用執行個體
Android各種Drawable基礎講解以及使用執行個體

十二、StateListDrawable:

 StateListDrawable管理一組drawable,每一個drawable都對應着一組狀态,狀态的選擇類似于java中的switch-case組合,按照順序比較狀态,當遇到比對的狀态後,就傳回對應的drawable,是以需要把最精确的比對放置在最前面,按照從精确到粗略的順序排列。

        StateListDrawable在Android中使用的非常廣泛,所有控件的背景基本上都使用了StateListDrawable,比如按鈕就具有很多狀态,按下狀态、選中狀态、預設狀态、禁用狀态等等,像這樣在不用的狀态下顯示效果不一樣的時候,就是需要使用StateListDrawable的時候。

在xml檔案中使用selector作為根節點來定義StateListDrawable,并使用item定義不同狀态下的drawable。定義如下XML:

<?xml version="1.0" encoding="utf-8"?>

<selector

    xmlns:android="http://schemas.android.com/apk/res/android"

    android:constantSize="false" //StateListDrawable的固有大小是否根據狀态而改變,預設false=根據狀态而改變

    android:dither="true"        //是否開啟抖動-讓高品質圖檔在低品質螢幕上依舊效果好,預設true開啟

    android:variablePadding="false" //padding是否根據狀态的改變而改變,不建議開啟(false)

    >

    <item android:state_pressed="true"  //Button被按下後卻沒有松開的狀态

        android:drawable="@color/colorAccent"/>

    <item android:state_focused="true"  //View擷取了焦點

        android:drawable="@color/colorPrimary"/>

    <item android:state_selected="true" //使用者選擇了View

        android:drawable="@color/colorPrimary"/>

    <item android:state_checked="true" //使用者選中了View,一般用于CheckBox這類在選中和沒有選中狀态之間切換的View

        android:drawable="@drawable/ic_launcher_background"/>

    <item android:state_enabled="true" //View處于可用狀态

        android:drawable="@drawable/ic_launcher_foreground"/>

    <item android:drawable="#FFFFFF"/> //預設Drawable: 按順序向下比對,需要放在最下方,因為可以比對任何狀态

</selector>

Drawable的使用:

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

    <!--這個是輸入框邊框變色-->
    <item android:state_window_focused="false">
        <shape android:shape="rectangle">
            <solid
                android:color="#FFFFFFFF"/>
            <corners
                android:radius="3dp"/>
            <padding
                android:left="10dp"
                android:right="10dp"/>
            <stroke
                android:width="1dp"
                android:color="#BDC7D8"/>
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape android:shape="rectangle" >
            <solid
                android:color="#FFFFFFFF"/>
            <corners
                android:radius="3dp"/>
            <padding
                android:left="10dp"
                android:right="10dp"/>
            <stroke
                android:width="1dp"
                android:color="#cf1b18"/>
        </shape>
    </item>
</selector>      

layout:檔案

<EditText
    android:id="@+id/btn_selector_1"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_gravity="center_horizontal"
    android:hint="請輸入資訊"
    android:layout_margin="15dp"
    android:singleLine="true"
    android:layout_marginTop="20dp"
    android:background="@drawable/selector_drawable"/>      

效果圖:

Android各種Drawable基礎講解以及使用執行個體