1. 概述
在實(shí)際開(kāi)發(fā)的過(guò)程中,除了廣為人知的利用 StateListDrawable 設(shè)置按鈕點(diǎn)擊特效,我們有時(shí)可能會(huì)接到一些這樣的需求,比如要求我們的頭像顯示成圓形或者圓角矩形,甚至要加上可變顏色的邊框,或者要求你做一套啟動(dòng)、暫停、快進(jìn)和快退的視頻控制按鈕并且可以改變按鈕圖標(biāo)顏色??赡苣承r(shí)候第一反應(yīng)就是用自定義 View 來(lái)實(shí)現(xiàn),但是如果熟悉了 Drawable 的用法之后,這些效果同樣可以利用它來(lái)完成,而選擇哪種 Drawable 來(lái)實(shí)現(xiàn)也大有講究。
Google 官方文檔中列出了各種各種各樣的 Drawable,那么它們都是如何使用的呢?
本系列文章將分為兩個(gè)部分,介紹其中大部分 Drawable 的用法。
2. BitmapDrawable
BitmapDrawable 可以看作是對(duì) Bitmap 的一種包裝,它可以設(shè)定 Bitmap 的顯示方式、位置等屬性。
2.1 語(yǔ)法
BitmapDrawable 對(duì)應(yīng) <bitmap> 標(biāo)簽定義,xml 語(yǔ)法如下:
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@[package:]drawable/drawable_resource"
android:antialias=["true" | "false"]
android:dither=["true" | "false"]
android:filter=["true" | "false"]
android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
"fill_vertical" | "center_horizontal" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"]
android:mipMap=["true" | "false"]
android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />
其中各個(gè)屬性的含義分別是:
屬性 | 含義 |
---|---|
src | Bitmap 對(duì)象的引用路徑 |
antialias | 抗鋸齒效果,建議開(kāi)啟 |
dither | 是否防抖動(dòng)。當(dāng)位圖像素與屏幕像素不匹配(如 ARGB_8888 的位圖顯示在 RGB_565 的屏幕上)時(shí),防止圖片失真,建議開(kāi)啟 |
filter | 是否啟用位圖過(guò)濾。開(kāi)啟后,當(dāng)圖片進(jìn)行拉伸或者壓縮時(shí),能夠進(jìn)行平滑過(guò)渡 |
gravity | 當(dāng)位圖尺寸小于容器尺寸時(shí)在容器中的擺放位置 |
mipMap | 啟用或停用 mipmap 提示,默認(rèn)為 false |
tileMode | 平鋪模式。默認(rèn):disable;clamp:復(fù)制邊沿的顏色;repeat:水平和垂直方向重復(fù)繪制圖片;mirror:水平和垂直方向交替鏡像進(jìn)行重復(fù)繪制 |
2.2 用法示例
下面以定義一個(gè)使用圖片作為背景的 Drawable 為例,展示 BitmapDrawable 的簡(jiǎn)單實(shí)用方法。
定義
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@mipmap/kakarotto"
android:antialias="true"
android:dither="true"
android:filter="true"
android:gravity="center"
android:tileMode="repeat"/>
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="@drawable/bitmap_drawable"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖
3. ShapeDrawable 和 GradientDrawable
官方文檔中對(duì) ShapeDrawable 的定義是這樣的:
A Drawable object that draws primitive shapes. A ShapeDrawable takes a
Shape
object and manages its presence on the screen. If no Shape is given, then the ShapeDrawable will default to aRectShape
.This object can be defined in an XML file with the
<shape>
element.
即它是一個(gè)用來(lái)繪制原始形狀的 Drawable 對(duì)象。
而對(duì) GradientDrawable 的定義是:
A Drawable with a color gradient for buttons, backgrounds, etc.
It can be defined in an XML file with the
<shape>
element. For more information, see the guide to Drawable Resources.
根據(jù)描述可知,它是一個(gè)具有色彩梯度(color gradient)的 Drawable。
3.1 語(yǔ)法
GradientDrawable 和 ShapeDrawable 都采用 shape 標(biāo)簽來(lái)定義,和 ShapeDrawable 最大的不同的就是它擁有 gradient 屬性,下面以 GradientDrawable 為例,講解 shape 標(biāo)簽的用法,它的語(yǔ)法如下:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle" | "oval" | "line" | "ring"] >
<corners
android:radius="integer"
android:topLeftRadius="integer"
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />
<gradient
android:angle="integer"
android:centerX="integer"
android:centerY="integer"
android:centerColor="integer"
android:endColor="color"
android:gradientRadius="integer"
android:startColor="color"
android:type=["linear" | "radial" | "sweep"]
android:usesLevel=["true" | "false"] />
<padding
android:left="integer"
android:top="integer"
android:right="integer"
android:bottom="integer" />
<size
android:width="integer"
android:height="integer" />
<solid
android:color="color" />
<stroke
android:width="integer"
android:color="color"
android:dashWidth="integer"
android:dashGap="integer" />
</shape>
其中各個(gè)屬性標(biāo)簽的含義分別是:
android:shape
表示形狀,它的值可以是 rectangle(矩形)、oval(橢圓)、line(橫線)和 ring(圓環(huán)),默認(rèn)為 rectangle。 此外,當(dāng)形狀值是 ring 的時(shí)候,還有一下幾個(gè)屬性可配置:
屬性 | 含義 |
---|---|
android:innerRadius | 圓環(huán)的內(nèi)半徑。與 innerRadiusRatio 同時(shí)設(shè)置時(shí),以 innerRadiusRatio 為準(zhǔn) |
android:innerRadiusRatio | 圓環(huán)的內(nèi)半徑占環(huán)寬度的比率 |
android:thickness | 圓環(huán)厚度。與 thicknessRatio同時(shí)設(shè)置時(shí),以 thicknessRatio 為準(zhǔn) |
android:thicknessRatio | 圓環(huán)的厚度占環(huán)寬度的比率 |
android:useLevel | 一般為 false,否則可能達(dá)不到預(yù)期顯示效果,除非把它當(dāng)作 LevelListDrawable 來(lái)使用 |
<corners>
<corners
android:radius="integer"
android:topLeftRadius="integer"
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />
指圖形的圓角半徑,僅當(dāng) shape 屬性為 rectangle 即形狀是矩形時(shí)生效,數(shù)值越小越接近直角,android:radius 同時(shí)設(shè)置四個(gè)角的半徑,其他四個(gè)屬性則可單獨(dú)設(shè)置某個(gè)角的半徑。
<gradient>
<gradient
android:angle="integer"
android:centerX="integer"
android:centerY="integer"
android:centerColor="integer"
android:endColor="color"
android:gradientRadius="integer"
android:startColor="color"
android:type=["linear" | "radial" | "sweep"]
android:usesLevel=["true" | "false"] />
表示顏色漸變,它的各個(gè)屬性值的含義分別是:
屬性 | 含義 |
---|---|
android:angle | 漸變的角度。必須是 45 的倍數(shù),默認(rèn)值為 0。0 為從左到右,90 為從上到下 |
android:centerX | 漸變中心的相對(duì) X 軸位置 (0 - 1.0) |
android:centerY | 漸變中心的相對(duì) Y 軸位置 (0 - 1.0) |
android:startColor | 漸變的起始顏色 |
android:centerColor | 漸變的中間顏色 |
android:endColor | 漸變的結(jié)束顏色 |
android:gradientRadius | 漸變的半徑,僅在 android:type="radial" 時(shí)適用
|
android:useLevel | 一般為 false,否則可能達(dá)不到預(yù)期顯示效果,除非把它當(dāng)作 LevelListDrawable 來(lái)使用 |
android:type | 漸變類別。它的值可以為:linear(線性),默認(rèn)值、radial(徑內(nèi)漸變)和sweep(掃描漸變) |
<padding>
距離內(nèi)容或者子元素的內(nèi)邊距,每個(gè)方向可以單獨(dú)設(shè)置。
<size>
設(shè)置 shape 大小,width 表示寬度,height 表示高度。需要注意的是,這個(gè)一般并不是 shape 的最終大小,如果用作 View 的背景,它的大小是由 View 的大小來(lái)決定的。
<solid>
表示純色填充,color 屬性為填充的顏色。
<stroke>
邊框描述,它的各個(gè)屬性值的含義分別是:
屬性 | 含義 |
---|---|
android:width | 邊框?qū)挾?/td> |
android:color | 邊框顏色 |
android:dashWidth | 虛線的線段寬度 |
android:dashGap | 虛線之間的空白間隔 |
需要注意的是,如果需要設(shè)置邊框虛線效果,則需要同時(shí)設(shè)置 dashWidth 和 dashGap 的值不為 0,否則無(wú)法顯示虛線效果。
3.2 用法示例
下面以定義一個(gè)圓角并帶有其他效果的 Drawable 為例,展示 GradientDrawable 的簡(jiǎn)單用法。
定義
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!--圓角半徑-->
<corners
android:topLeftRadius="15dp"
android:topRightRadius="15dp"
android:bottomLeftRadius="15dp"
android:bottomRightRadius="15dp"/>
<!--內(nèi)邊距-->
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
<!--漸變效果-->
<gradient android:angle="45"
android:type="linear"
android:startColor="#ff0000"
android:centerColor="#00ff00"
android:endColor="#0000ff" />
<!--預(yù)設(shè)大小-->
<size
android:width="200dp"
android:height="100dp" />
<!--邊框樣式-->
<stroke
android:width="2dp"
android:color="#000000"
android:dashWidth="7dp"
android:dashGap="3dp" />
</shape>
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".GradientDrawableActivity">
<Button
android:text="Button"
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@drawable/gradient_drawable"
android:id="@+id/textView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖
4. StateListDrawable
StateListDrawable 可以根據(jù)對(duì)象的狀態(tài)并使用不同的 item(Drawable) 對(duì)象來(lái)表示同一個(gè)圖形。如可以根據(jù) Button 的狀態(tài)(按下、獲取焦點(diǎn)等)來(lái)顯示不同的 Drawable 從而實(shí)現(xiàn)點(diǎn)擊的效果。
4.1 語(yǔ)法
定義 StateListDrawable 的語(yǔ)法格式如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:constantSize=["true" | "false"]
android:dither=["true" | "false"]
android:variablePadding=["true" | "false"]
android:autoMirrored=["true" | "false"]
android:enterFadeDuration="integer"
android:exitFadeDuration="integer">
<item
android:drawable="@[package:]drawable/drawable_resource"
android:state_pressed=["true" | "false"]
android:state_focused=["true" | "false"]
android:state_hovered=["true" | "false"]
android:state_selected=["true" | "false"]
android:state_checkable=["true" | "false"]
android:state_checked=["true" | "false"]
android:state_enabled=["true" | "false"]
android:state_activated=["true" | "false"]
android:state_window_focused=["true" | "false"] />
</selector>
StateListDrawable 的根標(biāo)簽為 <selector>,各個(gè)屬性標(biāo)簽的含義分別是:
android:constantSize
由于 StateListDrawable 會(huì)根據(jù)不同的狀態(tài)來(lái)顯示不同的 Drawable,而每個(gè) Drawable 的大小不一定相同,因此當(dāng) constantSize 屬性的值為 true 時(shí)表示固定大小(值為所有 Drawable 固有大小的最大值),值為 false 時(shí)則大小為當(dāng)前狀態(tài)下對(duì)應(yīng)的 Drawable 的大小。默認(rèn)值為 false。
android:variablePadding
表示 StateListDrawable 的 padding 值是否隨狀態(tài)的改變而改變,默認(rèn)為 false。
android:dither
是否開(kāi)啟抖動(dòng)效果,默認(rèn)為 true,建議開(kāi)啟。
android:autoMirrored
某些西亞國(guó)家文字是從右至左的,設(shè)置此值表示當(dāng)系統(tǒng)為 RTL (right-to-left) 布局的時(shí)候,是否對(duì)圖片進(jìn)行鏡像翻轉(zhuǎn)。
android:enterFadeDuration 和 android:exitFadeDuration
狀態(tài)改變時(shí)的淡入淡出效果的持續(xù)時(shí)間
<item>
每個(gè) item 表示一個(gè) Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現(xiàn)有的的 Drawable |
android:state_pressed | 是否處于被按下?tīng)顟B(tài) |
android:state_focused | 是否已得到焦點(diǎn)狀態(tài) |
android:state_hovered | 光標(biāo)是否停留在View的自身大小范圍內(nèi)的狀態(tài) |
android:state_selected | 是否處于被選中狀態(tài) |
android:state_checkable | 是否處于可勾選狀態(tài) |
android:state_checked | 是否處于已勾選狀態(tài) |
android:state_enabled | 是否處于可用狀態(tài) |
android:state_active | 是否處于激活狀態(tài) |
android:state_window_focused | 是否窗口已得到焦點(diǎn)狀態(tài) |
4.2 用法示例
下面以定制一個(gè)具有點(diǎn)擊效果 Button 的背景為例,展示 StateListDrawable 的用法。
定義
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android"
android:visible="true"
android:dither="true"
android:autoMirrored="true"
android:enterFadeDuration="200"
android:exitFadeDuration="200" >
<!--獲取焦點(diǎn)狀態(tài)-->
<item
android:state_focused="true"
android:drawable="@drawable/shape_dark" />
<!--按下?tīng)顟B(tài)-->
<item
android:state_pressed="true"
android:drawable="@drawable/shape_dark"/>
<!--默認(rèn)狀態(tài)-->
<item
android:drawable="@drawable/shape_light"/>
</selector>
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="@android:color/holo_orange_dark"
tools:context=".LayerDrawableActivity">
<Button
android:text="Button"
android:background="@drawable/drawable_state_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖
5. LayerDrawable
LayerDrawable 是管理 Drawable 列表的 Drawable。列表中的每個(gè) item 按照列表的順序繪制,列表中的最后 item 繪于頂部。
5.1 語(yǔ)法
定義 LayerDrawable 的語(yǔ)法格式如下:
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="@[package:]drawable/drawable_resource"
android:id="@[+][package:]id/resource_name"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"
android:left="dimension"
android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
"fill_vertical" | "center_horizontal" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"] />
</layer-list>
LayerDrawable 頂層標(biāo)簽為 <layer-list>,它可以包含多個(gè) <item> 標(biāo)簽,每個(gè) item 表示一個(gè) Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現(xiàn)有的的 Drawable |
android:id | item 的 id,使用"@+id/name"的形式表示??赏ㄟ^(guò) View.findViewById() 或者 Activity.findViewById() 方法查找到這個(gè) Drawable |
android:top、android:right、android:bottom、android:left | Drawable 相對(duì)于 View 在各個(gè)方向的偏移量 |
android:gravity | 尺寸小于容器尺寸時(shí)在容器中的擺放位置 |
5.2 用法示例
下面以定義一個(gè)圓角并帶陰影效果的 Drawable 為例,展示 LayerDrawable 的簡(jiǎn)單使用。
定義
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--內(nèi)部定義一個(gè) Drawable-->
<item
android:left="2dp"
android:top="4dp">
<shape>
<solid android:color="@android:color/darker_gray" />
<corners android:radius="10dp" />
</shape>
</item>
<!--指定現(xiàn)有的 Drawable-->
<item
android:bottom="4dp"
android:right="2dp"
android:drawable="@drawable/shape_light">
</item>
</layer-list>
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="@android:color/holo_orange_dark"
tools:context=".LayerDrawableActivity">
<LinearLayout
android:orientation="vertical"
android:background="@drawable/layer_drawable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_margin="20dp"
tools:layout_editor_absoluteY="331dp"
tools:layout_editor_absoluteX="190dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="I'm a title......."
android:textSize="20sp" />
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/darker_gray"
android:text="content content content content content content content content..."
android:textSize="16sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖
6. LevelListDrawable
LevelListDrawable 同樣表示一個(gè) Drawable 列表,列表中的每個(gè) item 都有一個(gè) level 值, LevelListDrawable 會(huì)根據(jù)不同的 level 在不同的 item 之間進(jìn)行切換。
6.1 語(yǔ)法
定義 LevelListDrawable 的語(yǔ)法格式如下:
<?xml version="1.0" encoding="utf-8"?>
<level-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="@drawable/drawable_resource"
android:maxLevel="integer"
android:minLevel="integer" />
</level-list>
LayerDrawable 根標(biāo)簽為 <layer-list>,它可以包含多個(gè) <item> 標(biāo)簽,每個(gè) item 表示一個(gè) Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現(xiàn)有的的 Drawable |
android:maxLevel | 該 item 允許的最大級(jí)別,取值范圍為[0, 10000] |
android:minLevel | 該 item 允許的最小級(jí)別,取值范圍為[0, 10000] |
6.2 用法示例
定義
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/kakarotto1"
android:maxLevel="0" />
<item
android:drawable="@drawable/kakarotto2"
android:maxLevel="1" />
<item
android:drawable="@drawable/kakarotto3"
android:maxLevel="2" />
<item
android:drawable="@drawable/kakarotto4"
android:maxLevel="3" />
<item
android:drawable="@drawable/kakarotto5"
android:maxLevel="4" />
</level-list>
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".GradientDrawableActivity">
<ImageView
android:text="Button"
android:layout_width="230dp"
android:layout_height="150dp"
android:src="@drawable/drawable_level_list"
android:id="@+id/img"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
然后控制 ImageView 的 level 即可顯示出效果:
class LevelListDrawableActivity : AppCompatActivity() {
lateinit var mImageView: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_level_list_drawable)
mImageView = findViewById(R.id.img)
for (i in 0..15) {
mHandler.sendEmptyMessageDelayed(i, (1000 * i).toLong())
}
}
var mHandler: Handler = object: Handler() {
override fun handleMessage(msg: Message?) {
msg?.what?.let { mImageView.setImageLevel(it%5) }
}
}
}
效果圖
7. InsetDrawable
在有些場(chǎng)景下,我們可能需要設(shè)置一個(gè)全屏的背景圖片,但又想讓背景圖片跟邊框留出一些間隙,這時(shí)使用 InsetDrawable 就能很好地解決問(wèn)題了。
7.1 語(yǔ)法
<?xml version="1.0" encoding="utf-8"?>
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:insetTop="dimension"
android:insetRight="dimension"
android:insetBottom="dimension"
android:insetLeft="dimension" />
根標(biāo)簽為 <inset>,它的各個(gè)屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現(xiàn)有的的 Drawable |
android:insetTop、android:insetRight、android:insetBottom、android:insetLeft | 內(nèi)容距離各個(gè)邊框的距離 |
7.2 用法示例
定義
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/shape_dark"
android:insetBottom="10dp"
android:insetTop="10dp"
android:insetLeft="10dp"
android:insetRight="10dp" />
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/drawable_inset">
<TextView
android:textSize="20sp"
android:text="TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖
8. ScaleDrawable
ScaleDrawable 可以根據(jù) level 值動(dòng)態(tài)地將 Drawable 進(jìn)行一定比例的縮放。當(dāng) level 的取值范圍為 [0, 10000],當(dāng) level 為 0 時(shí)表示隱藏;當(dāng) level 值為 1 時(shí),Drawable 的大小為初始化時(shí)的縮放比例,當(dāng) level 值為 10000 時(shí),Drawable 大小為 100% 縮放比例。
8.1 語(yǔ)法
定義 ScaleDrawable 的語(yǔ)法如下:
<?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" />
它的根標(biāo)簽為 <scale>,它的各個(gè)屬性的含義分別是:
android:drawable
drawable 資源,可引用現(xiàn)有的的 Drawable
android:scaleGravity
當(dāng)圖片尺寸小于 View 時(shí),設(shè)置這個(gè)屬性值可以對(duì)圖片進(jìn)行定位,可以使用 ”|“ 符號(hào)組合使用,所有值的含義分別為:
值 | 說(shuō)明 |
---|---|
top | 將對(duì)象放在其容器頂部,不改變其大小。 |
bottom | 將對(duì)象放在其容器底部,不改變其大小。 |
left | 將對(duì)象放在其容器左邊緣,不改變其大小。這是默認(rèn)值。 |
right | 將對(duì)象放在其容器右邊緣,不改變其大小。 |
center_vertical | 將對(duì)象放在其容器的垂直中心,不改變其大小。 |
fill_vertical | 按需要擴(kuò)展對(duì)象的垂直大小,使其完全適應(yīng)其容器。 |
center_horizontal | 將對(duì)象放在其容器的水平中心,不改變其大小。 |
fill_horizontal | 按需要擴(kuò)展對(duì)象的水平大小,使其完全適應(yīng)其容器。 |
center | 將對(duì)象放在其容器的水平和垂直軸中心,不改變其大小。 |
fill | 按需要擴(kuò)展對(duì)象的垂直大小,使其完全適應(yīng)其容器。 |
clip_vertical | 可設(shè)置為讓子元素的上邊緣和/或下邊緣裁剪至其容器邊界的附加選項(xiàng)。裁剪基于垂直重力:頂部重力裁剪上邊緣,底部重力裁剪下邊緣,任一重力不會(huì)同時(shí)裁剪兩邊。 |
clip_horizontal | 可設(shè)置為讓子元素的左邊和/或右邊裁剪至其容器邊界的附加選項(xiàng)。裁剪基于水平重力:左邊重力裁剪右邊緣,右邊重力裁剪左邊緣,任一重力不會(huì)同時(shí)裁剪兩邊。 |
android:scaleHeight
Drawable 高的縮放比例,值越高最終結(jié)果越小。
android:scaleWidth
Drawable 寬的縮放比例
8.2 用法示例
這里采用定制一個(gè)大小可變的背景為例,展示 ScaleDrawable 的簡(jiǎn)單用法。
定義
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/kakarotto"
android:scaleHeight="80%"
android:scaleWidth="80%"
android:scaleGravity="center" />
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="Button"
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@drawable/drawable_scale"
android:id="@+id/button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
class ScaleDrawableActivity : AppCompatActivity() {
lateinit var scaleDrawable: ScaleDrawable
var curLevel = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_scale_drawable)
scaleDrawable = findViewById<Button>(R.id.button).background as ScaleDrawable
scaleDrawable.level = 0
Observable.interval(200, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe {
scaleDrawable.level = curLevel
curLevel += 200
if (curLevel >= 10000) {
curLevel = 0
}
Log.e("gpj", "level ${curLevel}")
}
}
}
效果圖
9. ClipDrawable
與 ScaleDrawable 原理相同,ClipDrawable 則可以根據(jù) level 值動(dòng)態(tài)地將 Drawable 進(jìn)行一定比例的剪裁。當(dāng) level 的取值范圍為 [0, 10000],當(dāng) level 為 0 時(shí)表示隱藏;當(dāng) level 值為 1 時(shí),Drawable 的大小為初始化時(shí)的剪裁比例,當(dāng) level 值為 10000 時(shí),Drawable 大小為 100% 剪裁比例。
9.1 語(yǔ)法
定義 ClipDrawable 的語(yǔ)法規(guī)則如下:
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:clipOrientation=["horizontal" | "vertical"]
android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
"fill_vertical" | "center_horizontal" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"] />
它的根標(biāo)簽為 <clip>,各個(gè)屬性的含義分別是:
android:drawable
drawable 資源,可引用現(xiàn)有的的 Drawable
android:clipOrientation
剪裁方向,horizontal 表示水平方向剪裁,vertical 表示豎直方向剪裁
android:gravity
gravity 屬性需要配合 clipOrientation 來(lái)使用,可以使用 ”|“ 符號(hào)組合使用,所有值的含義分別為:
值 | 說(shuō)明 |
---|---|
top | 將對(duì)象放在其容器頂部,不改變其大小。當(dāng) clipOrientation 是 "vertical" 時(shí),在可繪制對(duì)象的底部裁剪。 |
bottom | 將對(duì)象放在其容器底部,不改變其大小。當(dāng) clipOrientation 是 "vertical" 時(shí),在可繪制對(duì)象的頂部裁剪。 |
left | 將對(duì)象放在其容器左邊緣,不改變其大小。這是默認(rèn)值。當(dāng) clipOrientation 是 "horizontal" 時(shí),在可繪制對(duì)象的右邊裁剪。這是默認(rèn)值。 |
right | 將對(duì)象放在其容器右邊緣,不改變其大小。當(dāng) clipOrientation 是 "horizontal" 時(shí),在可繪制對(duì)象的左邊裁剪。 |
center_vertical | 將對(duì)象放在其容器的垂直中心,不改變其大小。裁剪行為與重力為 "center" 時(shí)相同。 |
fill_vertical | 按需要擴(kuò)展對(duì)象的垂直大小,使其完全適應(yīng)其容器。當(dāng) clipOrientation 是 "vertical" 時(shí),不會(huì)進(jìn)行裁剪,因?yàn)榭衫L制對(duì)象會(huì)填充垂直空間(除非可繪制對(duì)象級(jí)別為 0,此時(shí)它不可見(jiàn))。 |
center_horizontal | 將對(duì)象放在其容器的水平中心,不改變其大小。裁剪行為與重力為 "center" 時(shí)相同。 |
fill_horizontal | 按需要擴(kuò)展對(duì)象的水平大小,使其完全適應(yīng)其容器。當(dāng) clipOrientation 是 "horizontal" 時(shí),不會(huì)進(jìn)行裁剪,因?yàn)榭衫L制對(duì)象會(huì)填充水平空間(除非可繪制對(duì)象級(jí)別為 0,此時(shí)它不可見(jiàn))。 |
center | 將對(duì)象放在其容器的水平和垂直軸中心,不改變其大小。當(dāng) clipOrientation 是 "horizontal" 時(shí),在左邊和右邊裁剪。當(dāng) clipOrientation 是 "vertical" 時(shí),在頂部和底部裁剪。 |
fill | 按需要擴(kuò)展對(duì)象的垂直大小,使其完全適應(yīng)其容器。不會(huì)進(jìn)行裁剪,因?yàn)榭衫L制對(duì)象會(huì)填充水平和垂直空間(除非可繪制對(duì)象級(jí)別為 0,此時(shí)它不可見(jiàn))。 |
clip_vertical | 可設(shè)置為讓子元素的上邊緣和/或下邊緣裁剪至其容器邊界的附加選項(xiàng)。裁剪基于垂直重力:頂部重力裁剪上邊緣,底部重力裁剪下邊緣,任一重力不會(huì)同時(shí)裁剪兩邊。 |
clip_horizontal | 可設(shè)置為讓子元素的左邊和/或右邊裁剪至其容器邊界的附加選項(xiàng)。裁剪基于水平重力:左邊重力裁剪右邊緣,右邊重力裁剪左邊緣,任一重力不會(huì)同時(shí)裁剪兩邊。 |
9.2 用法示例
定義
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:clipOrientation=["horizontal" | "vertical"]
android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
"fill_vertical" | "center_horizontal" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"] />
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="Button"
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@drawable/drawable_clip"
android:id="@+id/button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
class ClipDrawableActivity : AppCompatActivity() {
lateinit var clipDrawable: ClipDrawable
var curLevel = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_clip_drawable)
clipDrawable = findViewById<Button>(R.id.button).background as ClipDrawable
clipDrawable.level = 0
Observable.interval(50, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe {
clipDrawable.level = curLevel
curLevel += 200
if (curLevel >= 10000) {
curLevel = 0
}
Log.e("gpj", "level ${curLevel}")
}
}
}
效果圖
10. RotateDrawable
與 ScaleDrawable 和 ClipDrawable 類似,RotateDrawable 可以根據(jù) level 值將 Drawable 進(jìn)行動(dòng)態(tài)旋轉(zhuǎn)。
10.1 語(yǔ)法
RotateDrawable 的定義方法如下:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:visible=["true" | "false"]
android:fromDegrees="integer"
android:toDegrees="integer"
android:pivotX="percentage"
android:pivotY="percentage" />
它的根標(biāo)簽為 <clip>,各個(gè)屬性的含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現(xiàn)有的的 Drawable |
android:visible | 是否可見(jiàn) |
android:fromDegrees | 旋轉(zhuǎn)起始角度 |
android:toDegrees | 旋轉(zhuǎn)結(jié)束角度 |
android:pivotX | 旋轉(zhuǎn)中心位于 X 軸的百分比 |
android:pivotY | 旋轉(zhuǎn)中心位于 Y 軸的百分比 |
10.2 用法示例
下面以定義一個(gè)可旋轉(zhuǎn)的背景為例展示 RotateDrawable 的簡(jiǎn)單使用
定義
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/kakarotto"
android:fromDegrees="0"
android:toDegrees="180"
android:pivotX="50%"
android:pivotY="50%"/>
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="Button"
android:layout_width="200dp"
android:layout_height="100dp"
android:background="@drawable/drawable_rotate"
android:id="@+id/button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
class RotateDrawableActivity : AppCompatActivity() {
lateinit var rotateDrawable: RotateDrawable
var curLevel = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_rotate_drawable)
rotateDrawable = findViewById<Button>(R.id.button).background as RotateDrawable
rotateDrawable.level = 0
Observable.interval(50, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe {
rotateDrawable.level = curLevel
curLevel += 200
if (curLevel >= 10000) {
curLevel = 0
}
Log.e("gpj", "level ${curLevel}")
}
}
}
效果圖
11. TransitionDrawable
有時(shí)候我們可能需要在兩個(gè)圖片切換的時(shí)候增加漸變效果,除了使用動(dòng)畫(huà)之外,這里還可以用 TransitionDrawable 輕松實(shí)現(xiàn)。
11.1 語(yǔ)法
<?xml version="1.0" encoding="utf-8"?>
<transition
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="@[package:]drawable/drawable_resource"
android:id="@[+][package:]id/resource_name"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"
android:left="dimension" />
</transition>
它的根標(biāo)簽為 <transition>,它可以包含多個(gè) <item> 標(biāo)簽,每個(gè) item 表示一個(gè) Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現(xiàn)有的的 Drawable |
android:id | iitem 的 id,使用"@+id/name"的形式表示??赏ㄟ^(guò) View.findViewById() 或者 Activity.findViewById() 方法查找到這個(gè) Drawable |
android:top、android:right、android:bottom、android:left | Drawable 相對(duì)于 View 在各個(gè)方向的偏移量 |
11.2 用法示例
這里定義一個(gè)淡入淡出效果的圖片切換效果,展示 TransitionDrawable 的基本使用。
定義
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/kakarotto1" />
<item android:drawable="@drawable/kakarotto2" />
</transition>
使用
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="230dp"
android:layout_height="150dp"
android:background="@drawable/drawable_transition"
android:id="@+id/img"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
class TransitionDrawableActivity : AppCompatActivity() {
lateinit var disposable: Disposable
var reverse = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_transition_drawable)
var transitionDrawable = findViewById<ImageView>(R.id.img).background as TransitionDrawable
Observable.interval(3000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<Long> {
override fun onSubscribe(d: Disposable) {
disposable = d
}
override fun onComplete() {
}
override fun onNext(t: Long) {
if (!reverse) {
transitionDrawable.startTransition(3000)
reverse = true
} else {
transitionDrawable.reverseTransition(3000)
reverse = false
}
}
override fun onError(e: Throwable) {
}
})
}
效果圖
好了,傳統(tǒng)的 Drawable 就介紹完了,但是隨著 Android 版本的更新,Drawable 家族也不斷得有新成員加入進(jìn)來(lái),讓開(kāi)發(fā)者有了更多的選擇,下一部分文章,我將介紹從 Android 5.0(API 21) 之后加入進(jìn)來(lái)的幾個(gè)成員。
附:文章中的 Demo 地址:https://github.com/guanpj/DrawableDemo