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" />