Android的Drawable

Drawable簡介

提到Drawable,第一反應肯定是存放圖片的位置,實際上,Drawable并不僅僅指圖片。它可以理解為一種圖片的概念,比如顏色填充,也可以理解為一種圖片。

Drawable類是一個抽象類,它有BitmapDrawable,ShapeDrawable,LayerDrawable,StateListDrawable等常用子類。

BitmapDrawable

BitmapDrawable就是一張圖片,通過src屬性定義指向的圖片資源,然后對該圖片進行相關設置主要屬性如下:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_launcher"
    android:gravity="bottom"http://設定圖片在容器中的位置,默認值為fill,在水平和豎直方向填充容器
    android:antialias="true"http://設置抗鋸齒
    android:tint 給圖片著色,比如圖片本來是黑色的,著色后可以變成白色
    android:tintMode 著色模式,也是API Level 21(Android 5.0)才添加的屬性
    android:alpha 設置圖片的透明度,取值范圍為0.0~1.0之間,API Level最低要求是11,即Android 3.0
    android:filter="true"http://開啟過濾效果
    android:dither="true"http://開啟抖動效果
    android:tileMode="clamp"http://設置平鋪方式,disable,clamp,repeat,mirror
   >
</bitmap>
//使用代碼進行動態設置:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
        BitmapDrawable bitmapDrawable = new BitmapDrawable(bitmap);
        bitmapDrawable.setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        bitmapDrawable.setAntiAlias(true);
        bitmapDrawable.setDither(true);

除了針對常見圖片的BitmapDrawable之外,NinePatchDrawable對應的是.9圖片,用法同BitmapDrawable一樣,根標簽是nine-patch

ColorDrawable

ColorDrawable用純色填充一塊區域,使用也最簡單,只有一個屬性,color:

<color xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorBlack">
</color>
//代碼設定:
ColorDrawable colorDrawable = new ColorDrawable(0xffff0000);
//使用顏色:
mImageView.setBackground(new ColorDrawable(0xffff0000));
mImageView.setBackgroundColor(Color.argb(255,00,255,00));

Android中對顏色的設定采用ARGB模式,xml中可以不指定alpha值,但是在代碼中使用十六進制數值設置顏色時,必須制定alpha值,否則默認為0x00,全透明,是看不到顏色的。

GradientDrawable(ShapeDrawable)

GradientDrawable表示一個漸變區域,可以實現線性漸變、發散漸變、和平鋪漸變。它的主要屬性如下:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="line">//設置Shape形狀,rectangle(矩形),oval(橢圓),line(直線),ring(圓形)四個可選值
<!-- 下面的屬性只有在android:shape="ring時可用:
android:innerRadius         尺寸,內環的半徑。
android:innerRadiusRatio    浮點型,以環的寬度比率來表示內環的半徑,
android:thickness           尺寸,環的厚度
android:thicknessRatio      浮點型,以環的寬度比率來表示環的厚度,例如,如果android:thicknessRatio="2",
android:useLevel            boolean值,如果當做是LevelListDrawable使用時值為true,否則為false.  "-->
    <corners //只有rectangle有效,用來設置四個角的圓角半徑
        android:radius="50px"http://對四個角統一設置,優先級較低,會被以下屬性覆蓋
        android:topLeftRadius="40dp"
        android:topRightRadius="40dp"
        android:bottomLeftRadius="40dp"
        android:bottomRightRadius="40dp"/>
    <gradient//漸變效果
        android:angle="45"http://漸變的方向角度,必須為45的倍數,默認為0
        android:centerX="100"http://漸變中心點X坐標
        android:centerY="250"
        android:startColor="@color/colorBlack"http://漸變起始色
        android:centerColor="@color/colorDarkGreen"http://漸變中間顏色
        android:endColor="@color/colorWhite"http://結束顏色
        android:gradientRadius="50dp"http://漸變半徑,只有type值為radial時有效
        android:type="linear"http://漸變類型,有Linear(線性),radial(徑向),sweep(掃描線)三種。默認為線型漸變
        android:useLevel="false"/>//一般為false,只有當Drawable作為StateListDrawable使用才設置true
    <solid//純色填充,與gradient互斥
        android:color="@color/colorDarkGreen"/>
    <stroke//Shape描邊效果
        android:width="5dp"http://描邊寬度
        android:color="@color/colorLightRed"
        android:dashWidth="15dp"http://線條長度
        android:dashGap="5dp"/>//線條間距
    <padding//設置內邊距
        android:left="5dp"
        android:right="5dp"
        android:bottom="5dp"
        android:top="5dp"/>
    <size//設置尺寸。Drawable本身是沒有尺寸概念的,使用getIntrinsicWidth/Height獲取到的值是-1。通過Size設定Drawable固有尺寸。
            但是作為背景的時候,Shape仍然會拉伸為適合view的大小
        android:width="200dp"
        android:height="200dp"/>
</shape>

LayerDrawable

LayerDrawable包含多個item,每個item表示一個drawable,LayerDrawable將所包含的item放置在不同的層次上,第一個item在最底層,依次向上疊加:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:left="2dp"
        android:top="4dp">
        <shape>
            <solid android:color="@android:color/darker_gray" />
            <corners android:radius="10dp" />
        </shape>
    </item>
    <item
        android:bottom="4dp"
        android:right="2dp">
        <shape>
            <solid android:color="#FFFFFF" />
            <corners android:radius="10dp" />
        </shape>
    </item>
</layer-list>

item子節點可以直接定義一個Drawable,也可以使用android:drawable屬性來引用一個Drawable,layer-list沒有屬性節點,只包含Item子節點。Item節點屬性除了android:drawable,還有android:top/left/right/bottom用來設定各個方向的偏移距離

StateListDrawable

StatelistDrawable也是一個Drawable集合,每個Drawable對應View的一種狀態,只要用在設置View的背景。它使用selector標簽:

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize="true" //默認為false。因為狀態改變的時候會切換到不同的Drawable,大小也是不同的,設置為true表示尺寸固定不變
    android:dither="true"
    android:variablePadding="true"http://默認為false,表示padding不隨著狀態的改變而變化。
    android:enterFadeDuration="500"http://狀態改變時切入的動作事件,ms
    android:exitFadeDuration="500">
    <item
        android:drawable="@color/colorBlack"http://指定Drawable資源,也可以是color
        android:state_pressed="true"http://按下狀態
        android:state_focused="true"http://獲取到焦點
        android:state_hovered="true"http://API14加入,true表示鼠標在其上滑動
        android:state_selected="true"http://選擇了view
        android:state_checkable="true"http://可選擇狀態。類似于enable,它用來設置CheckBox等可勾選的控件
        android:state_checked="true"http://是否選中狀態
        android:state_enabled="false"http://是否可用狀態。通常只設置false
        android:state_activated="true"/是否被激活狀態,API Level 11及以上才支持,可通過代碼調用控件的setActivated(boolean)方法設置是否激活該控件
        android:state_window_focused="true"/>//當前窗口是否獲取焦點。比如彈出對話框就會失去焦點
</selector>

系統會根據View的當前狀態從selector中選擇對應的item,選擇的時候會從上向下一直找到第一條匹配的item,通常會設置一個默認的item放在最后,不設置任何的狀態。這樣當系統在上邊的item中找不到對應的狀態時,就會選擇最后一個默認的item,它不附帶任何狀態,可以匹配給所以狀態。

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 當前窗口失去焦點時 -->
    <item android:color="@android:color/black" android:state_window_focused="false" />
    <!-- 不可用時 -->
    <item android:color="@android:color/background_light" android:state_enabled="false" />
    <!-- 按壓時 -->
    <item android:color="@android:color/holo_blue_light" android:state_pressed="true" />
    <!-- 被選中時 -->
    <item android:color="@android:color/holo_green_dark" android:state_selected="true" />
    <!-- 被激活時 -->
    <item android:color="@android:color/holo_green_light" android:state_activated="true" />
    <!-- 默認時 -->
    <item android:color="@android:color/white" />
</selector>
//在控件中使用Drawable
<Button 
    android:id="@+id/btn_default"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    android:background="@drawable/bg_btn_selector"
    android:text="默認按鈕"
    android:textColor="@color/text_btn_selector" />

LevelListDrawable

LevelListDrawable也是一系列Drawable集合,它通過Level來匹配item。

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:drawable="@color/colorBlack"
    android:maxLevel="10000"
    android:minLevel="0"/>
</level-list>

item子節點除了指定Drawable之外,只有兩個屬性android:maxLevel指定最高Level(10000),android:minLevel指定最低Level(0),在這兩個值中間就會匹配該item。匹配的時候也是從上向下,直到匹配到一條合適的item 。所以,通常只需要指定maxLevel就可以了,將item按maxLevel從小到大依次排列下來。

Level的設置使用Drawable的setLevel方法來設定。如果是作為ImageView的前景,也可以通過ImageView的setImageLevel來設定。

TransitionDrawable

transition其實是繼承自layer-list的,只是,transition只能管理兩層drawable,另外提供了兩層drawable之間切換的方法,切換時還會有淡入淡出的動畫效果。示例代碼如下:

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/on" />
    <item android:drawable="@drawable/off" />
</transition>

然后在控件中指定背景:

<Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/transition_drawable"
        />

transition標簽生成的Drawable對應的類為TransitionDrawable,要切換時,需要主動調用TransitionDrawable的startTransition()方法,參數為動畫的毫秒數,也可以調用reverseTransition()方法逆向切換。

Button mButton = (Button) findViewById(R.id.btn1);
TransitionDrawable transitionDrawable = mButton.getBackground();
transitionDrawable.startTransition(500); //正向切換,即從第一個drawable切換到第二個
transitionDrawable.reverseTransition(500); //逆向切換,即從第二個drawable切換回第一個

InsetDrawable

InsetDrawable使用<inset>標簽,可以將指定的Drawable內嵌到自己當中,特殊的是它可以設置四周的間距,作為背景時,設定值為背景與view邊框的距離,用layerList同樣可以實現。

android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標簽
android:visible 設置初始的可見性狀態,默認為false
android:insetLeft 左邊距
android:insetRight 右邊距
android:insetTop 頂部邊距
android:insetBottom 底部邊距
android:inset 設置統一邊距,會覆蓋上面四個屬性,但API Level要求為21,即Android 5.0

ScaleDrawable

ScaleDrawable使用<scale>標簽,它可以對指定的drawable進行縮放。它的scaleGravity屬性作用同BItmap一樣。另外還有兩個特殊屬性,scaleHeight和scaleWidt指定寬和高的縮放比例,接收百分比數值。需要注意的是,ScaleDrawable縮放效果不僅僅受scaleHeight和scaleWidth影響,還要指定Level。默認的Level為0,這時候ScaleDrawable是不會繪制的。下面來看一個例子:

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:scaleGravity="center"
    android:scaleHeight="30%"http://實際大小約為70%
    android:scaleWidth="30%"
    android:level="1"/>//API 24以上才支持
//在控件中使用:這時候是看不到圖片的,沒有設置Level,圖片不會繪制出來
    <ImageView
        android:id="@+id/scaleimg"
        android:src="@drawable/scaledraw"
        android:layout_width="150dp"
        android:layout_height="150dp"/>
//設置Level:
mScaleImageView.setImageLevel(1);

注意的是,Level對縮放比例的影響,Level值越大,Drawable就越大,如果設置為10000(Level最大值),那么不管縮放比例設置多少,都不會進行縮放。而scaleHeight和scaleWidth相反,值越大,Drawable越小。

ClipDrawable

ClipDrawable用來對Drawable進行裁剪,它也是根據Level來決定裁剪范圍,10000表示不裁剪,0表示全部裁剪,就看不到了。裁剪的方向通過clipOritation來設置vertical和horizontal,除此之外還有一個Gravity屬性,它和clipOritation一起決定了裁剪方式。
Gravity有以下取值:

top: Drawable放在容器頂部,豎直裁剪的時候從底部開始
bottom:Drawable放在容器底部,豎直裁剪時從頂部開始
left:默認值。Drawable放在容器左邊,水平裁剪時從右邊開始
right:放在右邊,水平裁剪從左邊開始
center_vertical:Drawable豎直居中,不改變大小,豎直裁剪從上下同時開始
fill_vertical:豎直方向填充容器。豎直裁剪的時候,只有clipDrawable的level為0,才有裁剪行為
center_horizontal:水平居中,不改變大小,水平裁剪從左右同時開始
fill_horizontal:水平填充,水平裁剪只有當clipDrawable的level為0,才有裁剪行為
center:水平和垂直居中,豎直方向上下,水平方向左右同時裁剪
fill:水平和豎直方向填充容器,只有當clipDrawable的level為0,才有裁剪行為

其他標簽

  • rotate
    <rotate>標簽用來控制Drawable的旋轉,主要用以下屬性:

    android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標簽
    android:fromDegrees 起始的角度度數
    android:toDegrees 結束的角度度數,正數表示順時針,負數表示逆時針
    android:pivotX 旋轉中心的X坐標,浮點數或是百分比。浮點數表示相對于drawable的左邊緣距離單位為px,如5; 百分比表示相對于drawable的左邊緣距離按百分比計算,如5%; 另一種百分比表示相對于父容器的左邊緣,如5%p; 一般設置為50%表示在drawable中心
    android:pivotY 旋轉中心的Y坐標
    android:visible 設置初始的可見性狀態,默認為false

    將一張圖片旋轉180度代碼如下:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_arrow"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="180" />

rotate同樣與Level有關。Level值從0-10000分別對應fromDegrees和toDegrees,比如Level設置5000就會旋轉90度。因為level值默認為0,所以默認是不會旋轉的,如果要旋轉的話可以將android:fromDegrees直接設置180度,開始的狀態就已經完成旋轉了。

  • animation-list
    <animation-list>用來將一系列drawable構建成幀動畫。通過添加item子標簽設置每一幀使用的drawable資源,以及每一幀持續的時間。示例代碼如下:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@drawable/anim1"
        android:duration="1000" />
    <item
        android:drawable="@mipmap/anim2"
        android:duration="1000" />
    <item
        android:drawable="@mipmap/anim3"
        android:duration="1000" />
</animation-list>

android:oneshot屬性設置是否循環播放,設為true時,只播放一輪就結束,設為false時,則會輪詢播放。
android:duration屬性設置該幀持續的時間,以毫秒數為單位。
animation-list對應的Drawable類為AnimationDrawable,要讓動畫運行起來,需要主動調用AnimationDrawable的start()方法。另外,如果在Activity的onCreate()方法里直接調用start()方法會沒有效果,因為view還沒有初始化完成是播放不了動畫的。

  • animation-rotate

    rotate標簽只是將原有的drawable轉個角度變成另一個drawable,它是靜態的。而animated-rotate則會讓drawable不停地做旋轉動畫。
    animated-rotate可設置的屬性只有四個:

android:drawable 指定drawable資源,如果不設置該屬性,也可以定義drawable類型的子標簽
android:pivotX 旋轉中心的X坐標
android:pivotY 旋轉中心的Y坐標
android:visible 設置初始的可見性狀態,默認為false

示例代碼:

<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/img_daisy"
    android:pivotX="50%"
    android:pivotY="50%"
    android:visible="false" />
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容