Android Drawable子類整理

概述

Drawable資源是Android應用中使用最普遍的資源,它不只可使用各類格式的圖片資源,也可使用多種xml文件資源。

1.一種能夠在Canvas上進行繪製的抽象的概念; 2.顏色、圖片等均可以是一個Drawable; 3.Drawable能夠經過XML定義,或者經過代碼建立; 4.Android中Drawable是一個抽象類,每一個具體的Drawable都是其子類;html

Drawable的分類

Drawable的子類包括ColorDrawable、GradientDrawable、BitmapDrawable、NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、RotateDrawable、AnimationDrawable、LayerDrawable、StateListDrawable、TransitionDrawable、VectorDrawable、ShapeDrawablejava

1.ColorDrawable

A specialized Drawable that fills the Canvas with a specified color.android

ColorDrawable是最簡單的Drawable,也是平時用的最多的,好比:canvas

android:background = "@color/colorAccent"app

ColorDrawable是一個專門用來使用指定的顏色來填充畫布的Drawable,當它被繪製到畫布上時會使用一種指定的顏色填充Paint,在畫布上繪製出一塊單色區域。ide

在xml文件中使用color做爲根節點來建立ColorDrawable,它只有一個android:color屬性,經過它來決定ColorDrawable的顏色,這個顏色一旦設置以後,就不能直接修改了。post

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

經過java代碼也能夠建立ColorDrawable,代碼以下:動畫

ColorDrawable drawable = new ColorDrawable(0xff000000);this

2.BitmapDrawable

A Drawable that wraps a bitmap and can be tiled, stretched, or aligned.spa

BitmapDrawable是對bitmap的一種包裝,能夠設置它包裝的bitmap在BitmapDrawable區域內的繪製方式,如平鋪、拉伸填充或者保持圖片原始尺寸,也能夠在BitmapDrawable區域內部使用gravity指定的對齊方式。

在xml文件中使用bitmap做爲根節點來定義BitmapDrawable。

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/arrow_down"
    android:tileMode="mirror"
    android:antialias="true"
    android:dither="true"
    />

其中,src爲引用的圖片資源;tileMode屬性表示平鋪模式,一共有4中屬性:mirror,repeat,clamp,disabled;dither屬性表示是否開啓抖動,通常爲true;antialias屬性表示是否開啓抗鋸齒功能,通常爲true; 也可使用java代碼實現上述相同的效果,等價的java代碼以下:

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.arrow_down);
BitmapDrawable mBitmapDrawable = new BitmapDrawable(bitmap);
mBitmapDrawable.setTileModeXY(TileMode.MIRROR,TileMode.MIRROR);
mBitmapDrawable.setAntiAlias(true);
mBitmapDrawable.setDither(true);
mDrawable = mBitmapDrawable;

3.GradientDrawable

A Drawable with a color gradient for buttons, backgrounds, etc.

GradientDrawable表示一個漸變區域,能夠實現線性漸變、發散漸變和平鋪漸變效果; 在xml文件中使用shape做爲根節點來建立GradientDrawable,它包含不少屬性和子節點,具體以下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle | oval | ring | line">
    //                矩形      
    //內部填充色
    <solid android:color="@color/red" />
    //圓角半徑
    <corners android:radius="5dp" />
    //邊框顏色和寬度
    <stroke android:color="@color/orange" android:width="5dp" />
     //漸變色
    <gradient
         android:angle="integer" //漸變角度(默認爲0,即從左到右),須爲45的倍數,爲0時從左到右
                                 //爲90時從上到下,該屬性僅對線性漸變有效
        android:centerX="integer"           //漸變中心X的相對位置,範圍從0~1
        android:centerY="integer"           //漸變中心Y的相對位置,範圍從0~1
        android:startColor="color"          //顏色漸變的開始顏色
        android:centerColor="integer"       //顏色漸變的中心顏色
         android:endColor="color"            //顏色漸變的結束顏色
        android:gradientRadius="integer"    //漸變半徑,只有當type爲radial時才能使用
        android:type=["linear" | "radial" | "sweep"] //默認值爲linear,即線性漸變,radial(放射性漸變),sweep(掃描式漸變)
        android:useLevel=["true" | "false"]     //設置爲false纔有漸變效果
        />

    //指定大小
    <size android:width="45dp" android:height="45dp" />
    //內邊距
    <padding 
        android:left="5dp" android:top="5dp"
        android:right="5dp" android:bottom="5dp" />

在代碼中動態建立GradientDrawable樣例以下:

private Gradient getDrawable(int radius,int fillColor,iunt width,int strokeColor) {
    GradientDrawable gradientDrawable = new GradientDrawable();
    gradientDrawable.setCornerRadius(radius);
    gradientDrawable.setColor(fillColor);
    gradientDrawable.setStroke(width,strokeColor);
    return gradientDrawable;
}

可實現drawable中shape樣式的功能,setColor()至關於shape中的填充色,setCornerRadius()用來設置shape的圓角半徑,setStroke(int width,int color)用來設置邊框的寬度和顏色。

4.ScaleDrawable

ScaleDrawable是對一個Drawable進行縮放操做,能夠根據level屬性控制這個drawable的縮放比例,也能夠設置它在容器中的對齊方式。在xml文件中使用scale做爲根節點來建立ScaleDrawable,建立ScaleDrawable的代碼以下:

<?xml version="1.0" encoding="utf-8"?>
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                          "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                          "center" | "fill" | "clip_vertical" | "clip_horizontal"]
    android:scaleHeight="percentage"
    android:scaleWidth="percentage" />
  • android:drawable 引用一個drawable資源;
  • android:scaleHeight 縮放的高度,以百分比的方式表示drawable的縮放;
  • android:scaleWidth 縮放的寬度,以百分比的方式表示drawable的縮放;
  • android:scaleGravity 指定縮放後的gravity的位置,必須爲如下的一個或多個值(多個值之間用「|」間隔)
    • top 將這個對象放在容器的頂部,不改變其大小;
    • bottom 將這個對象放在容器的底部,不改變其大小;
    • left 將這個對象放在容器的左部,不改變其大小;
    • right 將這個對象放在容器的右部,不改變其大小;
    • center_vertical 將對象垂直居中,不改變其大小;
    • fill_vertical 若是須要的話,該對象的垂直尺寸將增長,以便徹底填充它的容器;
    • center_horizontal 將對象水平居中,不改變其大小;
    • fill_horizontal 若是須要的話,該對象的水平尺寸將增長,以便徹底填充它的容器;
    • center 將對象放在其容器的中心位置,不改變它的大小;
    • fill 若是須要的話,該對象的水平和垂直方向上的尺寸將增長,以便徹底填充它的容器;
    • clip_vertical 能夠設置爲在其容器邊界上的頂部或底部邊緣的附加選項;該剪輯是基於垂直gravity:一個頂部gravity剪輯的底部邊緣,底部gravity剪輯的頂部邊緣;
    • clip_horizontal 與clip_vertical相似,只是剪輯是基於水平gravity

定義一個scale.xml:

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

而後在layout中使用:

<ImageView   
    android:id="@+id/imgView"  
    android:src="@drawable/scale"  
    android:layout_width="wrap_content"  
    android:layout_height="wrap_content"/>

可是若是直接運行,圖片並無顯示,緣由是draw()方法中只有當getLevel()!=0時才繪製;而咱們在沒有se't'Level()時,默認getLevel()爲0;

比例縮放的計算公式以下:

w -= (int) (w * (10000 - level) * mState.mScaleWidth / 10000); h -= (int) (h * (10000 - level) * mState.mScaleHeight / 10000);

當level設置爲10000時,顯示爲圖片原始大小;當level爲0時,圖片不顯示;所以通常將level設置爲1,這樣圖片就會根據android:scaleHeight和android:scaleWidth進行相應的縮放。

5.RotateDrawable

RotateDrawable用來控制drawable的旋轉,在xml文件中使用rotate做爲根元素來建立RotateDrawable:

rotate.xml
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:pivotX="50%"
    android:pivotY="50%"
    android:visible="true"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:drawable="@mipmap/cd" >
</rotate>

使用時經過ImageView的src屬性對該RotateDrawable進行引用

<ImageView
        android:id = "@+id/iv"
        android:layout_width = "wrap_content"
        android:layout_height = "wrap_content"
        android:src = "@drawable/rotate"
        />
  • android:drawable 指定將要進行旋轉操做的Drawable對象;
  • android:visible 視圖是否可見,默認值爲false;
  • android:pivotX 表示旋轉軸心在x軸橫座標上的位置,用百分比表示,表示在當前drawable總寬度百分之幾的位置;
  • android:pivotY 表示旋轉軸心在y軸縱座標上的位置,用百分比表示,表示在當前drawable總高度百分之幾的位置;
  • android:fromDegrees 表示起始角度,值大於0,則表示順時針旋轉,值小於0,則表示逆時針旋轉。
  • android:toDegrees 表示終點角度,值大於0,則表示順時針旋轉,值小於0,則表示逆時針旋轉。

在activity中經過iv.getDrawable().setLevel(int level)對RotateDrawable進行控制(level的值在0~10000之間)

6.AnimationDrawable

AnimationDrawable是用來實現Android幀動畫的,就是把一系列的Drawable按照必定的順序一幀幀的播放;只適用於不要進行控制的幀動畫,例如刷新時的進度條素材。 在xml文件中使用<animation-list>做爲根節點來建立AnimationDrawable;相關的屬性方法以下:

  • android:oneshot 設置是否須要循環播放,false爲循環播放;
  • duration 幀間隔時間,一般咱們會設置爲300毫秒;

再得到AnimationDrawable實例後,須要調用它的start方法來播放動畫,另外要注意在onCreate()方法中調用的話,是沒有任何效果的,由於View還沒完成初始化;咱們能夠用簡單的handler來延遲播放動畫;其餘的實現方法可參考如下連接:Android AnimationDrawable運行的幾種方式

實際使用實例:

  • 先定義一個AnimationDrawable的xml資源文件(eg:animation.xml):
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <item
        android:drawable="@mipmap/ic_pull_to_refresh_loading01"
        android:duration="100" />

    <item
        android:drawable="@mipmap/ic_pull_to_refresh_loading02"
        android:duration="100" />
    <item
        android:drawable="@mipmap/ic_pull_to_refresh_loading03"
        android:duration="100" />
    <item
        android:drawable="@mipmap/ic_pull_to_refresh_loading04"
        android:duration="100" />
    <item
        android:drawable="@mipmap/ic_pull_to_refresh_loading05"
        android:duration="100" />
    <item
        android:drawable="@mipmap/ic_pull_to_refresh_loading06"
        android:duration="100" />

</animation-list>
  • 在activity_main.xml中設置ImageView的src屬性(android:src = "@drawable/animation"),而後在MainActivity中:
public class MainActivity extends AppCompatActivity {
    private ImageView img_show;
    private AnimationDrawable ad;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        img_show = (ImageView) findViewById(R.id.img_show);
        //核心代碼
        ad = (AnimationDrawable)img_show.getDrawable();
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                ad.start();
            }
        },300);
    }
}

7.LayerDrawable

LayerDrawable對應的xml標籤是<layer-list>,它表示一種層次化的Drawable集合,經過將不一樣的Drawable放置在不一樣的層上從而達到一種疊加後的效果。 在xml文件中建立LayerDrawable的代碼以下:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <bitmap android:src="@drawable/type_newgmae_icon"
            android:gravity="center"
            />
    </item>

    <item android:top="15dp" android:left="15dp">
        <bitmap android:src="@drawable/type_networkgame_icon"
            android:gravity="center"/>
    </item>

    <item android:top="30dp" android:left="30dp">
        <bitmap android:src="@drawable/type_necessary_icon"
            android:gravity="center"
             />
    </item>
</layer-list>

實現的效果以下:

8.ClipDrawable

A Drawable that clips another Drawable based on this Drawable's current level value. You can control how much the child Drawable gets clipped in width and height based on the level, as well as a gravity to control where it is placed in its overall container. Most often used to implement things like progress bars, by increasing the drawable's level with setLevel().

一種能夠根據當前的level值來裁剪出另外一個Drawable的Drawable,能夠經過調節level值來控制裁剪的寬和高,以及裁剪內容佔整個容器的權重,常常經過Drawable的setLevel()方法來增長顯示比例以實現相似進度條的效果。 level的範圍是0~10000,在ClipDrawable中,0表示的是徹底裁剪,即整個Drawable都不可見,10000表示不裁剪。 相關的源碼以下:

int w = bounds.width();
final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
if ((mState.mOrientation & HORIZONTAL) != 0) {
        w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;
    }

int h = bounds.height();
final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
if ((mState.mOrientation & VERTICAL) != 0) {
      h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;
    }

在xml文件中使用<clip>根節點來建立ClipDrawable,屬性以下: | 屬性名 | 功能 | | ------ | :---- | | android:clipOrientation | 裁剪的方向(horizontal、vertical) | | android:drawable | 引用一個drawable資源 | | android:gravity | 指定在drawable中剪切的位置|

  • 使用:
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:drawable="@drawable/image1"
    android:gravity="bottom" />
  • 而後將它設置給ImageView,能夠做爲src,也能夠做爲background;
<ImageView 
    android:id = "@+id/iv_clip"
    android:layout_width = "100dp"
    android:layout_height = "100dp"
    android:src = "@drawable/clip_drawable" />
  • 最後在代碼中給ClipDrawable設置等級
ImageView iv = findViewById(R.id.iv_clip);
ClipDrawable clipDrawable = (ClipDrawable)iv.getDrawable();
clipDrawable.setLevel(2000); //裁剪80%的區域

自定義ClipDrawable,主要是重寫draw(Canvas canvas)方法;

使用樣例: (實現圓形加載進度條)

  • clip_drawable.xml
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
     android:drawable="@mipmap/circle"
     android:gravity="bottom"
     android:clipOrientation="vertical"
     >
</clip>
  • activity_main.xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.SearchActivity"
    >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/iv_clip"
        android:src="@drawable/clip_drawable"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        />
    //顯示進度
    <TextView
        android:id="@+id/tv_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textColor="#de000000"
        android:text="0%"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
  • MainActivity.java
private Timer timer;
    private TimerTask timerTask;
    private ClipDrawable clipDrawable;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what != 0) {
                clipDrawable.setLevel(msg.what);
                tv_progress.setText(String.valueOf(msg.what*100/10000)+"%");
            } else {
                clipDrawable.setLevel(0);
                tv_progress.setText("0%");
            }
        }
    }
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        clipDrawable = (ClipDrawable)iv_clip.getDrawable();
        clipDrawable.setLevel(0);
        timer = new Timer();
        timerTask = new TimerTask() {
            @Override
            public void run() {
                if (clipDrawable.getLevel() <= 10000) {
                    handler.sendEmptyMessage(clipDrawable.getLevel()+25);
                } else {
                    handler.setEmptyMessage(0);
                }
            }
        };
        timer.schedule(timerTask,1000,50);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (timer != null) {
            timer.cancel();
            timer.purge();
            timer = null;
        }
    }

效果圖以下: 樣例1 ==> 樣例2

9.StateListDrawable

Lets you assign a number of graphic images to a single Drawable and swap out the visible item by a string ID value.

StateListDrawable能夠根據view的不一樣狀態來展現不一樣的drawable;例如一個按鈕不點擊時背景爲綠色,點擊後變爲橙色,用來動態設置TextView、Button、ImageView等組件在不一樣狀態下的背景/前景顯示效果;

StateListDrawable對應的xml根元素爲<selector>,而每一個selector中能夠放置多個item元素,每一個item元素能夠設置如下兩個屬性:

  • android:color或android:drawable:用來指定顏色或drawable資源;
  • android:state_xxx:用來指定一個特定的狀態 經常使用的屬性以下: | 屬性 | 功能描述| |----|---| |android:constantSize|StateListDrawable的大小是否隨着View的狀態的改變而改變,默認值爲false(隨着改變拉伸自身大小);true爲固定大小| |android:state_pressed|控件是否被按下| |android:state_focused|是否獲取控件焦點| |android:state_selected|控件是否被選擇| |android:state_checked|控件是否被勾選| |android:state_enabled|控件是否可用| |android:state_hovered|光標是否懸停,一般與state_focused相同| |android:state_checkable|控件能否被勾選,例如:checkbox| |android:state_activated|是否被激活| |android:state_window_focused|應用程序是否在前臺,當有通知欄被拉下來或者一個對話框彈出的時候應用程序就不在前臺了|

10.TransitionDrawable

Transition是一個特殊的Drawable對象,能夠實現兩個drawable資源之間淡入淡出的效果。 xml屬性以下: | 屬性名| 描述 | |----|:---| |android:drawable| 用來渲染圖層的drawable資源| |android:left| 圖層的左側座標| |android:top| 圖層的頂部座標| |android:right|圖層的右側座標| |android:bottom|圖層的底部座標| |android:id|圖層的標識符|

使用方式:

  • 先定義一個transition_simple.xml:
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable = "@mipmap/pic_first" />
    <item android:drawable = "@mipmap/pic_second" />
  • 而後定義一個ImageView對象(不須要添加src屬性):
<ImageView
    android:id = "@+id/iv_transition"
    android:layout_width = "100dp"
    android:layout_height = "100dp"
    />
  • 在onCreate()方法中:
ImageView iv = findViewById(R.id.iv_transition);
TransitionDrawable transition = (TransitionDrawable)getResources().getDrawable(R.drawable.transition_simple);
iv.setImageDrawable(transition);
transition.startTransition(2000);

須要調用startTransition()方法才能啓動兩層間的切換動畫;也能夠調用reverseTransition()方法反過來播放。

11.InsetDrawable

InsetDrawable表示一個drawable根據指定的距離嵌入到另一個drawable內部。(咱們看到的仍是同一張圖片,只是會空出一些邊距);當控件須要的背景比實際的邊框小的時候比較適合使用InsetDrawable; 在xml文件中經過<inset>做爲根元素來建立InsetDrawable,具體的屬性值以下: | 屬性 | 描述 | | ---- | :----| | android:drawable|引用的drawable資源| | android:insetTop|與頂部的距離 | | android:insetBottom|與底部的距離| | android:insetLeft|與左側的距離| | android:insetRight|與右側的距離|

使用:

  • 新建一個inset.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/guess_you_like_bg"
    android:insetTop="20dp"
    android:insetBottom="20dp"
    android:insetLeft="20dp"
    android:insetRight="20dp"/>
  • 經過控件的background屬性中引用該xml文件:
<ImageView 
    android:id = "@+id/iv_show"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/inset"
    />
  • 效果圖以下: example
相關文章
相關標籤/搜索