今天來看看這個Drawable的使用
主要參考官方文檔:https://developer.android.com/guide/topics/resources/drawable-resource
Drawable是圖形的一般概念臊泌,是指可在屏幕上繪制的圖形虚婿,以及可使用 getDrawable(int) 等 API 檢索箭券,或應(yīng)用到擁有 android:drawable 和 android:icon 等屬性的其他 XML 資源的圖形益楼。可繪制對象包含以下多種類型
(可以跳過這個部分 直接第一條分割線以下開始):
Bitmap File (本文已講解)
位圖圖形文件(.png、.jpg 或 .gif)。來源于BitmapDrawable
。
Nine-Patch File (不常用)
具有可伸縮區(qū)域的 PNG 文件雇初,支持根據(jù)內(nèi)容調(diào)整圖像大小 (.9.png)。來源于NinePatchDrawable
减响。
Layer List (本文已講解)
管理其他可繪制對象陣列的可繪制對象抵皱。這些可繪制對象按陣列順序繪制,因此索引最大的元素繪制于頂部辩蛋。來源于LayerDrawable
呻畸。
State List (本文已講解)
此 XML 文件用于為不同狀態(tài)引用不同位圖圖形(例如,按下按鈕時使用不同圖像)悼院。來源于StateListDrawable
伤为。
Level List (本文已講解)
此 XML 文件用于定義管理大量備選可繪制對象的可繪制對象,每個可繪制對象都配有最大備選數(shù)量据途。來源于LevelListDrawable
绞愚。
Transition Drawable
此 XML 文件用于定義可在兩種可繪制對象資源之間交錯淡出的可繪制對象。來源于TransitionDrawable
颖医。
Inset Drawable
此 XML 文件用于定義以指定距離插入其他可繪制對象的可繪制對象位衩。當(dāng)視圖需要小于視圖實際邊界的背景可繪制對象時,此類可繪制對象非常有用熔萧。
Clip Drawable
此 XML 文件用于定義對其他可繪制對象進(jìn)行裁剪(根據(jù)其當(dāng)前級別值)的可繪制對象糖驴。來源于ClipDrawable
僚祷。
Scale Drawable
此 XML 文件用于定義更改其他可繪制對象大小(根據(jù)其當(dāng)前級別值)的可繪制對象贮缕。來源于ScaleDrawable
Shape Drawable (本文已講解)
此 XML 文件用于定義幾何形狀(包括顏色和漸變)辙谜。來源于` GradientDrawable。
接下來我把經(jīng)常會使用的到的一些drawable的一些用法總結(jié)在下邊:
一. Shape Drawable
1.1 首先從一個例子開始
假如我們開發(fā)中需需要做一個圓角的感昼,背景漸變的按鈕就像這樣:(有沒有大海的感覺装哆?)
應(yīng)該怎么做?
你會自然而然的想到使用ShapeDrawable
步驟如下定嗓,在drawable文件夾右鍵--->New--->Drawable Resource File
然后在
my_shape_1
中輸入如下內(nèi)容:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
<gradient
android:startColor="#b0e0e6"
android:centerColor="#66cdaa"
android:endColor="#d2b48c"
/>
</shape>
最后在設(shè)置button的background就好了
android:background="@drawable/my_shap_1"
在這個例子中我們使用到了Shape Drawable
在shape標(biāo)簽中設(shè)置android:shape="rectangle"
表明形狀為正方形
然后再corners標(biāo)簽中設(shè)置四個圓角為10dp
最后再gradient標(biāo)簽中設(shè)置了開始蜕琴,中間,結(jié)束 三個顏色 完成漸變
這樣就完成了
1.2 Shape Drawable介紹和語法
用于在 XML 文件中定義的通用形狀宵溅。
文件位置:
res/drawable/filename.xml
文件名用作資源 ID凌简。
語法如下(直接在官方文檔上的圖)
1.3 常用標(biāo)簽和屬性講解
1.3.1 <shape>
根元素(必備)
shape中常用屬性只有一條:
android:shape
:用于設(shè)置形狀
可以設(shè)置四個有效值:android:shape=["rectangle" | "oval" | "line" | "ring"]
分別對應(yīng) 矩形,橢圓(長寬相等時為圓形)层玲,線号醉,環(huán)
其中rectangle
和oval
最常用反症。
1.3.2 <corners>
用于設(shè)置矩形圓角辛块,僅當(dāng)形狀為矩形時適用。
常用屬性:
android:radius
:設(shè)置所有四個圓角的半徑 (單位dp)
當(dāng)然在截圖中可以看到還有四條屬性
可以分別單獨設(shè)置四個圓角半徑铅碍,會覆蓋android:radius
1.3.3 <solid>
用于填充形狀的純色
只有一條常用屬性:
android:color
:確定填充顏色
1.3.4 <gradient>
指定形狀的漸變顏色润绵。
常用屬性:
android:startColor
:起始顏色
android:centerColor
:中間顏色
android:endColor
:結(jié)束顏色
android:angle
:顏色漸變的角度方向 0 為從左到右,90 為從上到上胞谈。必須是 45 的倍數(shù)尘盼。默認(rèn)值為 0。
以下屬性自己在Android studio中試一下烦绳,很簡單卿捎,但不好描述:
android:centerX
漸變中心的相對 X 軸位置 (0 ~ 1.0)。
android:centerY
漸變中心的相對 Y 軸位置 (0 ~ 1.0)径密。
android:type
要應(yīng)用的漸變圖案的類型午阵。有效值為:
"linear" 線性漸變。這是默認(rèn)值享扔。
"radial" 徑向漸變底桂。起始顏色為中心顏色。
"sweep" 流線型漸變惧眠。
android:gradientRadius
漸變的半徑籽懦。僅在 android:type="radial" 時適用。
1.3.5 <stroke>
設(shè)置描邊線條
常用屬性:
android:width
描邊寬度
android:color
描邊顏色
android:dashWidth
設(shè)置虛線每個點長度
android:dashGap
設(shè)置虛線每個空白區(qū)域長度
二. State List Drawable
2.1 State List Drawable介紹和語法
State List Drawable會根據(jù)對象狀態(tài)氛魁,使用多個不同的圖像來表示同一個圖形暮顺。例如厅篓,Button 可以是多種不同狀態(tài)(按下,松開)拖云,并且您可利用狀態(tài)列表可繪制對象贷笛,為每種狀態(tài)提供不同的背景圖片。在每個狀態(tài)變更期間宙项,將從上到下遍歷狀態(tài)列表乏苦,并使用第一個與當(dāng)前狀態(tài)匹配的項目 —此選擇并非基于“最佳匹配”,而是選擇符合狀態(tài)最低條件的第一個項目尤筐。
說白了就是給某個組件添加背景選擇器, 比如一個按鈕 按下和離開狀態(tài)會有不同背景表現(xiàn)汇荐。
文件位置:
res/drawable/filename.xml
文件名用作資源 ID。
語法如下:
2.2 常用標(biāo)簽和屬性介紹
2.2.1 <selector>
根元素(必備)
這個沒什么好說的 android屬性固定值
xmlns:android="http://schemas.android.com/apk/res/android"
2.2.2 <item>
android:drawable
確定此情況時 item的繪制資源內(nèi)容(shape drawable)
其他屬性就是item確定此item對應(yīng)的控件狀態(tài)盆繁。在每個狀態(tài)變更期間掀淘,將從上到下遍歷狀態(tài)列表,并使用第一個與當(dāng)前狀態(tài)匹配的item —此選擇并非基于“最佳匹配”油昂,而是選擇符合狀態(tài)最低條件的第一個項目革娄。
需要注意的是item和狀態(tài)是一對多的關(guān)系,比如item包含了“勾選”和“按下”狀態(tài)冕碟,那控件處于勾選或者按下時拦惋,會顯示該item。
這里總共10個狀態(tài)安寺,但不是每個控件都包含所有狀態(tài)厕妖,比如Button只有按下和松開兩種狀態(tài)。比如輸入框有獲取焦點等狀態(tài)挑庶,在實際使用中靈活選擇使用言秸。
當(dāng)item不指定狀態(tài)時,作為默認(rèn)狀態(tài)迎捺,通常置于list最底部举畸。
2.3 例子(我們可以用它來做什么?)
現(xiàn)在按鈕在這里凳枝,需要顯示點擊效果:
這里就使用shpae和state相互配合來完成
第一步在剛剛的例子基礎(chǔ)上創(chuàng)建my_shape_2
抄沮,內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
<solid android:color="#b0e0e6" />
</shape>
第二步在創(chuàng)建my_selector_1
內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!--按下狀態(tài)-->
<item android:drawable="@drawable/my_shape_2" android:state_pressed="true" />
<!--默認(rèn)狀態(tài)-->
<item android:drawable="@drawable/my_shape_1" />
</selector>
第二步設(shè)置button:
android:background="@drawable/my_selector_1
三. Layer List Drawable
其實學(xué)會了前邊兩個,后邊的都非常簡單也好理解了范舀,這個layer-list
可以理解為一堆item從下到上進(jìn)行疊加重疊合是。
3.1 語法如下
3.2 常用標(biāo)簽和屬性介紹
3.2.1 <layer-list>
根元素(必備)
這個沒什么好說的 android屬性固定值
xmlns:android="http://schemas.android.com/apk/res/android"
3.2.2 <item>
android:drawable
調(diào)用drawable資源,確定此item繪制的內(nèi)容锭环,例如shape
android:id
資源 ID聪全。此可繪制對象的唯一資源 ID。要為此項新建資源 ID辅辩,請使用以下形式:"@+id/*name*"
难礼。加號表示應(yīng)創(chuàng)建為新 ID娃圆。您可以使用此 ID 檢索和修改擁有 View.findViewById()
或 Activity.findViewById()
的可繪制對象。
這個屬性非常關(guān)鍵蛾茉,我們可以通過id指定item所繪制的資源讼呢,比如進(jìn)度條有兩個需要繪制的地方分別是進(jìn)度條本身和背景,這個時候就可以通過background和progress來指定了
android:top
android:right
android:bottom
android:left
控制item在各個方向的偏移量 體現(xiàn)疊加效果
當(dāng)然和<selector>中的item一樣谦炬,其內(nèi)部也可以包含<bitmap>標(biāo)簽悦屏,調(diào)用mipmap資源顯示圖片
3.3 例子(我們可以用它來做什么?):
3.3.1 體現(xiàn)層疊效果1:
3.3.2 體現(xiàn)層疊效果2:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/strawberry1"></item>
<item
android:drawable="@drawable/strawberry2"
android:left="30dp"
android:top="30dp">
</item>
<item
android:drawable="@drawable/strawberry3"
android:left="60dp"
android:top="60dp">
</item>
</layer-list>
可以看到隨著位移增大键思,圖片在慢慢變小础爬,如果希望它大小不變,可以使用嵌套的 <bitmap> 元素為每個具有“中心”重力的項目定義可繪制對象資源吼鳞。這可確保沒有圖像會為了適應(yīng)容器的大小而縮放看蚜,因為偏移圖像會造成大小調(diào)整。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:src="@drawable/strawberry1" android:gravity="center"/>
</item>
<item
android:left="30dp"
android:top="30dp">
<bitmap android:src="@drawable/strawberry2" android:gravity="center"/>
</item>
<item
android:left="60dp"
android:top="60dp">
<bitmap android:src="@drawable/strawberry3" android:gravity="center"/>
</item>
</layer-list>
3.3.3 實現(xiàn)陰影效果
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/my_shape_2" />
<item
android:bottom="5dp"
android:drawable="@drawable/my_shape_1"
android:right="5dp" />
</layer-list>
四. Bitmap File
這個其實在我們之前使用草莓的例子中就是使用到了赔桌,將bitmap嵌入item中,現(xiàn)在完整的講解一下供炎。
位圖文件:
位圖文件是 .png
、.jpg
或 .gif
文件疾党。當(dāng)您將任一位圖文件保存到 res/drawable/
目錄中時音诫,Android 會為其創(chuàng)建 Drawable
資源。很簡單仿贬,直接跳過纽竣。
XML 位圖:
XML 位圖是在 XML 文件中定義的資源墓贿,指向位圖文件茧泪。實際上是原始位圖文件的別名。XML 可以指定位圖的其他屬性聋袋,例如抖動和層疊队伟。
4.1 語法:
4.2 標(biāo)簽和屬性介紹
只有一個標(biāo)簽<bitmap>
xmlns:android
定義 XML 命名空間,其必須是 "http://schemas.android.com/apk/res/android"幽勒。這僅當(dāng) <bitmap> 是根元素時才需要嗜侮,當(dāng) <bitmap> 嵌套在 <item> 內(nèi)時不需要。
android:src
可繪制對象資源啥容。必備锈颗。引用可繪制對象資源。這個資源可是圖片也可以是其他任drawable咪惠,例如shape
android:antialias
是否啟用抗鋸齒(犧牲清晰度击吱,換來流暢度)
android:filter
啟用或停用位圖過濾。當(dāng)位圖收縮或拉伸以使其外觀平滑時使用過濾遥昧。
android:gravity
設(shè)置位圖的比重覆醇,位圖會根據(jù)比重設(shè)置出現(xiàn)在容器不同位置
android:tileMode
定義平鋪模式朵纷。當(dāng)平鋪模式啟用時,位圖會重復(fù)永脓。重力在平鋪模式啟用時將被忽略袍辞。
alpha
透明度0~1.0
五. Level list drawable
管理大量備選可繪制對象的可繪制對象,每個可繪制對象都配有最大備選數(shù)量常摧。若使用 setLevel()
設(shè)置可繪制對象的級別值搅吁,則會加載級別列表中 android:maxLevel
值大于或等于傳遞至方法的值的可繪制對象資源。
語法:
標(biāo)簽和屬性介紹:
<level-list>
這必須是根元素落午。包含一個或多個 <item> 元素似芝。
屬性:
xmlns:android
字符串。必備板甘。定義 XML 命名空間党瓮,其必須是 "http://schemas.android.com/apk/res/android"。
<item>
定義要在某特定級別使用的可繪制對象盐类。
屬性:
android:drawable
可繪制對象資源寞奸。必備。引用要插入的可繪制對象資源在跳。
android:maxLevel
整型枪萄。此項目允許的最高級別。
android:minLevel
整型猫妙。此項目允許的最低級別瓷翻。
這里有一個很好的例子:例如開燈關(guān)燈
https://blog.csdn.net/zzldm/article/details/52982105
感覺這個level-list能實現(xiàn)的效果,使用其他方式都能實現(xiàn)割坠,這個更規(guī)范一點齐帚,項目中有一個手電筒開關(guān)的功能,改為level-list方式彼哼,并且setImageLevel這個方法对妄,似乎可以和屬性動畫配合使用
一個例子:
還是用到之前的草莓,先創(chuàng)建level-list文件敢朱,my_level_list_1
:
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:maxLevel="1"
>
<bitmap android:src="@drawable/strawberry1" />
</item>
<item
android:maxLevel="2"
>
<bitmap android:src="@drawable/strawberry2" />
</item>
<item
android:maxLevel="3"
>
<bitmap android:src="@drawable/strawberry3" />
</item>
</level-list>
然后在布局文件的ImageView中引用:
<ImageView
android:id="@+id/draw_image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/my_level_list_1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
最后在activity中添加一些邏輯:
private fun initView() {
val drawable=draw_image.drawable
if(drawable is LevelListDrawable){
drawable.level=1
}
var level=1
draw_Btn.setOnClickListener {
drawable.level=level
if(level<3){
level+=1
}else{
level=1
}
}
}
這樣每點擊一下按鈕 我們的草莓就會變一個顏色
但其實這種效果直接使用image.setImage就可以實現(xiàn)了剪菱,
再思考一下,如果繪制對象不是ImageView呢拴签,比如button呢?
是不是可以這樣呢孝常?:(擴(kuò)展中的例子3)
val drawableB=draw_Btn.background
if(drawableB is LevelListDrawable){....}
那么這樣是否可以擴(kuò)展到所有的View呢?
答案是 可以蚓哩!
也就意味著 我們就可以隨心所欲的根據(jù)某種情況修改view的繪制表現(xiàn)构灸,并且只需要很簡單那的一句話:
drawable.level=n
擴(kuò)展
以上就是Drwable的基本知識了,那么接下來列舉一些綜合性的例子杖剪,來實踐一下:
例子1-圓角漸變的進(jìn)度條:
效果圖:
這個圓角漸變的開始按鈕我們已經(jīng)講過了冻押,下面分析一下這個進(jìn)度條驰贷,可以看到進(jìn)度條由兩部分組成,首先是進(jìn)度條的灰色背景洛巢,然后是顏色漸變的進(jìn)度
接下來簡單說一下實現(xiàn)步驟:
首先在布局文件中加入一個progress bar:
<ProgressBar
android:id="@+id/draw_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="300dp"
android:layout_height="10dp"
android:max="1000"
android:progressDrawable="@drawable/bg_progress"
/>
style="?android:attr/progressBarStyleHorizontal"
:設(shè)置為橫向進(jìn)度條(默認(rèn)為圓圈)
android:progressDrawable="@drawable/bg_progress"
:設(shè)置表現(xiàn)樣式括袒,下面創(chuàng)建bg_progress.xml
文件
內(nèi)容如下:
bg_progress.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 設(shè)置背景色 -->
<item android:id="@android:id/background">
<shape>
<corners android:radius="20dp"/>
<solid android:color="#a9a9a9"/>
</shape>
</item>
<!-- 設(shè)置進(jìn)度條顏色 -->
<item android:id="@android:id/progress">
<clip>
<shape>
<gradient
android:angle="180"
android:centerColor="#66cdaa"
android:startColor="#b0e0e6"
android:endColor="#d2b48c"
/>
<corners android:radius="20dp"/>
</shape>
</clip>
</item>
</layer-list>
這里是一個layer-list
,通過item繪制了背景和進(jìn)度條的表現(xiàn)
android:id="@android:id/background"
通過id來指定了這個item所繪制的內(nèi)容稿茉。
現(xiàn)在就好了锹锰,然后在activity中加入屬性動畫就能讓進(jìn)度條動起來了:
private fun initView() {
draw_Btn.setOnClickListener {
shoWLoading(3*1000)
}
}
private fun shoWLoading(duration: Long) {
draw_progress.visibility = View.VISIBLE
val progressAnim= ObjectAnimator.ofInt(draw_progress,"progress",0,1000)
progressAnim.duration = duration
//anim.interpolator = DecelerateInterpolator()//插值器
//動畫監(jiān)聽
progressAnim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
}
})
progressAnim.start()
}
例子2-在例子1的基礎(chǔ)上更優(yōu)化一下:
我們可以看到例子一中雖然進(jìn)度條的背景是圓角了,但是進(jìn)度加載過程中卻是平角的:
但我們明明在例子一中通過
<corners android:radius="20dp"/>
設(shè)置了進(jìn)度圓角漓库,為什么沒有生效呢恃慧?其實這個是
<clip>
所導(dǎo)致的,要解決這個問題渺蒿,不使用它就行了痢士,我們換成<scale>
:新建一個
bg_progress_p.xml
繪制出我們想要的進(jìn)圖條樣式
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="180"
android:centerColor="#66cdaa"
android:startColor="#b0e0e6"
android:endColor="#d2b48c"
/>
<corners android:radius="20dp"/>
</shape>
然后修改bg_progress.xml
的內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 設(shè)置背景色(黑色) -->
<item android:id="@android:id/background">
<shape>
<corners android:radius="20dp"/>
<solid android:color="#a9a9a9"/>
</shape>
</item>
<!-- 設(shè)置進(jìn)度條顏色(白色) -->
<item android:id="@android:id/progress">
<scale
android:scaleWidth="100%"
android:drawable="@drawable/bg_progress_p"
>
</scale>
</item>
</layer-list>
現(xiàn)在就好了:
例子3-使用level-list隨心所欲地修改繪制表現(xiàn)
效果:
可以看到這個button隨著進(jìn)度條到25%,50%茂装,75%怠蹂,100%,都改變了一次顏色少态。
實現(xiàn)方式也很簡單:首先在例子2的基礎(chǔ)上創(chuàng)建一個<level-list>
my_button_level
其內(nèi)容如下:
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/bg_progress_p"
android:maxLevel="1" />
<item
android:drawable="@drawable/bg_progress_p_red"
android:maxLevel="2" />
</level-list>
這里bg_progress_p
,bg_progress_p_red
參考之前的例子自己生成
然后在布局文件中修改button的屬性如下:
<Button
android:id="@+id/draw_Btn"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="@drawable/my_button_level"
android:text="開始進(jìn)度"
android:textColor="#ffffff"
/>
然后就可以activity的代碼了:
var drawableB:Drawable?=null
private fun initView() {
//獲取到 button的繪制對象drawableB
drawableB=draw_Btn.background
draw_Btn.setOnClickListener {
shoWLoading(5*1000)
}
}
private fun shoWLoading(duration: Long) {
val progressAnim= ObjectAnimator.ofInt(draw_progress,"progress",0,1000)
progressAnim.duration = duration
//動畫監(jiān)聽
progressAnim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
//動畫結(jié)束
super.onAnimationEnd(animation)
Log.d("動畫值", "動畫結(jié)束")
if(drawableB?.level==1){
drawableB?.level=2
}else{drawableB?.level=1}
}
})
//動畫值變化監(jiān)聽
progressAnim.addUpdateListener(AnimatorUpdateListener { animation ->
val value=animation.animatedValue as Int
anim_value.text= "${value/10.0}%"http://實際值按百分比顯示:(value/1000)*100 %
Log.d("動畫值", value.toString())
if(value==250||value==500||value==750){
if(drawableB?.level==1){
drawableB?.level=2
}else{drawableB?.level=1}
}
})
progressAnim.start()
}
就可以達(dá)到效果圖中的效果了城侧。
這里最關(guān)鍵的代碼其實就是
drawableB=draw_Btn.background
drawableB?.level=n
一句話就修改了button的繪制樣式,是不是很舒服彼妻。
這只是一個很簡單的例子嫌佑,這里的button可以是任何view,讓想法起飛一下侨歉,可以用很少的代碼屋摇,做出很多好看的效果