在實際開發的過程當中,除了廣爲人知的利用 StateListDrawable 設置按鈕點擊特效,咱們有時可能會接到一些這樣的需求,好比要求咱們的頭像顯示成圓形或者圓角矩形,甚至要加上可變顏色的邊框,或者要求你作一套啓動、暫停、快進和快退的視頻控制按鈕而且能夠改變按鈕圖標顏色。可能某些時候第一反應就是用自定義 View 來實現,可是若是熟悉了 Drawable 的用法以後,這些效果一樣能夠利用它來完成,而選擇哪一種 Drawable 來實現也大有講究。php
Google 官方文檔中列出了各類各類各樣的 Drawable,那麼它們都是如何使用的呢?html
本系列文章將分爲兩個部分,介紹其中大部分 Drawable 的用法。android
BitmapDrawable 能夠看做是對 Bitmap 的一種包裝,它能夠設定 Bitmap 的顯示方式、位置等屬性。git
BitmapDrawable 對應 <bitmap> 標籤訂義,xml 語法以下:github
<?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"] />
複製代碼
其中各個屬性的含義分別是:app
屬性 | 含義 |
---|---|
src | Bitmap 對象的引用路徑 |
antialias | 抗鋸齒效果,建議開啓 |
dither | 是否防抖動。當位圖像素與屏幕像素不匹配(如 ARGB_8888 的位圖顯示在 RGB_565 的屏幕上)時,防止圖片失真,建議開啓 |
filter | 是否啓用位圖過濾。開啓後,當圖片進行拉伸或者壓縮時,可以進行平滑過渡 |
gravity | 當位圖尺寸小於容器尺寸時在容器中的擺放位置 |
mipMap | 啓用或停用 mipmap 提示,默認爲 false |
tileMode | 平鋪模式。默認:disable;clamp:複製邊沿的顏色;repeat:水平和垂直方向重複繪製圖片;mirror:水平和垂直方向交替鏡像進行重複繪製 |
下面以定義一個使用圖片做爲背景的 Drawable 爲例,展現 BitmapDrawable 的簡單實用方法。ide
定義佈局
<?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>
複製代碼
效果圖ui
官方文檔中對 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.
即它是一個用來繪製原始形狀的 Drawable 對象。
而對 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.
根據描述可知,它是一個具備色彩梯度(color gradient)的 Drawable。
GradientDrawable 和 ShapeDrawable 都採用 shape 標籤來定義,和 ShapeDrawable 最大的不一樣的就是它擁有 gradient 屬性,下面以 GradientDrawable 爲例,講解 shape 標籤的用法,它的語法以下:
<?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>
複製代碼
其中各個屬性標籤的含義分別是:
android:shape
表示形狀,它的值能夠是 rectangle(矩形)、oval(橢圓)、line(橫線)和 ring(圓環),默認爲 rectangle。 此外,當形狀值是 ring 的時候,還有一下幾個屬性可配置:
屬性 | 含義 |
---|---|
android:innerRadius | 圓環的內半徑。與 innerRadiusRatio 同時設置時,以 innerRadiusRatio 爲準 |
android:innerRadiusRatio | 圓環的內半徑佔環寬度的比率 |
android:thickness | 圓環厚度。與 thicknessRatio同時設置時,以 thicknessRatio 爲準 |
android:thicknessRatio | 圓環的厚度佔環寬度的比率 |
android:useLevel | 通常爲 false,不然可能達不到預期顯示效果,除非把它看成 LevelListDrawable 來使用 |
<corners>
<corners android:radius="integer" android:topLeftRadius="integer" android:topRightRadius="integer" android:bottomLeftRadius="integer" android:bottomRightRadius="integer" />
複製代碼
指圖形的圓角半徑,僅當 shape 屬性爲 rectangle 即形狀是矩形時生效,數值越小越接近直角,android:radius 同時設置四個角的半徑,其餘四個屬性則可單獨設置某個角的半徑。
<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"] />
複製代碼
表示顏色漸變,它的各個屬性值的含義分別是:
屬性 | 含義 |
---|---|
android:angle | 漸變的角度。必須是 45 的倍數,默認值爲 0。0 爲從左到右,90 爲從上到下 |
android:centerX | 漸變中心的相對 X 軸位置 (0 - 1.0) |
android:centerY | 漸變中心的相對 Y 軸位置 (0 - 1.0) |
android:startColor | 漸變的起始顏色 |
android:centerColor | 漸變的中間顏色 |
android:endColor | 漸變的結束顏色 |
android:gradientRadius | 漸變的半徑,僅在 android:type="radial" 時適用 |
android:useLevel | 通常爲 false,不然可能達不到預期顯示效果,除非把它看成 LevelListDrawable 來使用 |
android:type | 漸變類別。它的值能夠爲:linear(線性),默認值、radial(徑內漸變)和sweep(掃描漸變) |
<padding>
距離內容或者子元素的內邊距,每一個方向能夠單獨設置。
<size>
設置 shape 大小,width 表示寬度,height 表示高度。須要注意的是,這個通常並非 shape 的最終大小,若是用做 View 的背景,它的大小是由 View 的大小來決定的。
<solid>
表示純色填充,color 屬性爲填充的顏色。
<stroke>
邊框描述,它的各個屬性值的含義分別是:
屬性 | 含義 |
---|---|
android:width | 邊框寬度 |
android:color | 邊框顏色 |
android:dashWidth | 虛線的線段寬度 |
android:dashGap | 虛線之間的空白間隔 |
須要注意的是,若是須要設置邊框虛線效果,則須要同時設置 dashWidth 和 dashGap 的值不爲 0,不然沒法顯示虛線效果。
下面以定義一個圓角並帶有其餘效果的 Drawable 爲例,展現 GradientDrawable 的簡單用法。
定義
<?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"/>
<!--內邊距-->
<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" />
<!--預設大小-->
<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>
複製代碼
效果圖
StateListDrawable 能夠根據對象的狀態並使用不一樣的 item(Drawable) 對象來表示同一個圖形。如能夠根據 Button 的狀態(按下、獲取焦點等)來顯示不一樣的 Drawable 從而實現點擊的效果。
定義 StateListDrawable 的語法格式以下:
<?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 的根標籤爲 **<selector>,**各個屬性標籤的含義分別是:
android:constantSize
因爲 StateListDrawable 會根據不一樣的狀態來顯示不一樣的 Drawable,而每一個 Drawable 的大小不必定相同,所以當 constantSize 屬性的值爲 true 時表示固定大小(值爲全部 Drawable 固有大小的最大值),值爲 false 時則大小爲當前狀態下對應的 Drawable 的大小。默認值爲 false。
android:variablePadding
表示 StateListDrawable 的 padding 值是否隨狀態的改變而改變,默認爲 false。
android:dither
是否開啓抖動效果,默認爲 true,建議開啓。
android:autoMirrored
某些西亞國家文字是從右至左的,設置此值表示當系統爲 RTL (right-to-left) 佈局的時候,是否對圖片進行鏡像翻轉。
android:enterFadeDuration 和 android:exitFadeDuration
狀態改變時的淡入淡出效果的持續時間
<item>
每一個 item 表示一個 Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現有的的 Drawable |
android:state_pressed | 是否處於被按下狀態 |
android:state_focused | 是否已獲得焦點狀態 |
android:state_hovered | 光標是否停留在View的自身大小範圍內的狀態 |
android:state_selected | 是否處於被選中狀態 |
android:state_checkable | 是否處於可勾選狀態 |
android:state_checked | 是否處於已勾選狀態 |
android:state_enabled | 是否處於可用狀態 |
android:state_active | 是否處於激活狀態 |
android:state_window_focused | 是否窗口已獲得焦點狀態 |
下面以定製一個具備點擊效果 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" >
<!--獲取焦點狀態-->
<item android:state_focused="true" android:drawable="@drawable/shape_dark" />
<!--按下狀態-->
<item android:state_pressed="true" android:drawable="@drawable/shape_dark"/>
<!--默認狀態-->
<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>
複製代碼
效果圖
LayerDrawable 是管理 Drawable 列表的 Drawable。列表中的每一個 item 按照列表的順序繪製,列表中的最後 item 繪於頂部。
定義 LayerDrawable 的語法格式以下:
<?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 頂層標籤爲 <layer-list>,它能夠包含多個 <item> 標籤,每一個 item 表示一個 Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現有的的 Drawable |
android:id | item 的 id,使用"@+id/name"的形式表示。可經過 View.findViewById() 或者 Activity.findViewById() 方法查找到這個 Drawable |
android:top、android:right、android:bottom、android:left | Drawable 相對於 View 在各個方向的偏移量 |
android:gravity | 尺寸小於容器尺寸時在容器中的擺放位置 |
下面以定義一個圓角並帶陰影效果的 Drawable 爲例,展現 LayerDrawable 的簡單使用。
定義
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--內部定義一個 Drawable-->
<item android:left="2dp" android:top="4dp">
<shape>
<solid android:color="@android:color/darker_gray" />
<corners android:radius="10dp" />
</shape>
</item>
<!--指定現有的 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>
複製代碼
效果圖
LevelListDrawable 一樣表示一個 Drawable 列表,列表中的每一個 item 都有一個 level 值, LevelListDrawable 會根據不一樣的 level 在不一樣的 item 之間進行切換。
定義 LevelListDrawable 的語法格式以下:
<?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 根標籤爲 <level-list>,它能夠包含多個 <item> 標籤,每一個 item 表示一個 Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現有的的 Drawable |
android:maxLevel | 該 item 容許的最大級別,取值範圍爲[0, 10000] |
android:minLevel | 該 item 容許的最小級別,取值範圍爲[0, 10000] |
定義
<?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) }
}
}
}
複製代碼
效果圖
在有些場景下,咱們可能須要設置一個全屏的背景圖片,但又想讓背景圖片跟邊框留出一些間隙,這時使用 InsetDrawable 就能很好地解決問題了。
<?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" />
複製代碼
根標籤爲 <inset>,它的各個屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現有的的 Drawable |
android:insetTop、android:insetRight、android:insetBottom、android:insetLeft | 內容距離各個邊框的距離 |
定義
<?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>
複製代碼
效果圖
ScaleDrawable 能夠根據 level 值動態地將 Drawable 進行必定比例的縮放。當 level 的取值範圍爲 [0, 10000],當 level 爲 0 時表示隱藏;當 level 值爲 1 時,Drawable 的大小爲初始化時的縮放比例,當 level 值爲 10000 時,Drawable 大小爲 100% 縮放比例。
定義 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" />
複製代碼
它的根標籤爲 <scale>,它的各個屬性的含義分別是:
android:drawable
drawable 資源,可引用現有的的 Drawable
android:scaleGravity
當圖片尺寸小於 View 時,設置這個屬性值能夠對圖片進行定位,可使用 」|「 符號組合使用,全部值的含義分別爲:
值 | 說明 |
---|---|
top | 將對象放在其容器頂部,不改變其大小。 |
bottom | 將對象放在其容器底部,不改變其大小。 |
left | 將對象放在其容器左邊緣,不改變其大小。這是默認值。 |
right | 將對象放在其容器右邊緣,不改變其大小。 |
center_vertical | 將對象放在其容器的垂直中心,不改變其大小。 |
fill_vertical | 按須要擴展對象的垂直大小,使其徹底適應其容器。 |
center_horizontal | 將對象放在其容器的水平中心,不改變其大小。 |
fill_horizontal | 按須要擴展對象的水平大小,使其徹底適應其容器。 |
center | 將對象放在其容器的水平和垂直軸中心,不改變其大小。 |
fill | 按須要擴展對象的垂直大小,使其徹底適應其容器。 |
clip_vertical | 可設置爲讓子元素的上邊緣和/或下邊緣裁剪至其容器邊界的附加選項。裁剪基於垂直重力:頂部重力裁剪上邊緣,底部重力裁剪下邊緣,任一重力不會同時裁剪兩邊。 |
clip_horizontal | 可設置爲讓子元素的左邊和/或右邊裁剪至其容器邊界的附加選項。裁剪基於水平重力:左邊重力裁剪右邊緣,右邊重力裁剪左邊緣,任一重力不會同時裁剪兩邊。 |
android:scaleHeight
Drawable 高的縮放比例,值越高最終結果越小。
android:scaleWidth
Drawable 寬的縮放比例
這裏採用定製一個大小可變的背景爲例,展現 ScaleDrawable 的簡單用法。
定義
<?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}")
}
}
}
複製代碼
效果圖
與 ScaleDrawable 原理相同,ClipDrawable 則能夠根據 level 值動態地將 Drawable 進行必定比例的剪裁。當 level 的取值範圍爲 [0, 10000],當 level 爲 0 時表示隱藏;當 level 值爲 1 時,Drawable 的大小爲初始化時的剪裁比例,當 level 值爲 10000 時,Drawable 大小爲 100% 剪裁比例。
定義 ClipDrawable 的語法規則以下:
<?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"] />
複製代碼
它的根標籤爲 <clip>,各個屬性的含義分別是:
android:drawable
drawable 資源,可引用現有的的 Drawable
android:clipOrientation
剪裁方向,horizontal 表示水平方向剪裁,vertical 表示豎直方向剪裁
android:gravity
gravity 屬性須要配合 clipOrientation 來使用,可使用 」|「 符號組合使用,全部值的含義分別爲:
值 | 說明 |
---|---|
top | 將對象放在其容器頂部,不改變其大小。當 clipOrientation 是 "vertical" 時,在可繪製對象的底部裁剪。 |
bottom | 將對象放在其容器底部,不改變其大小。當 clipOrientation 是 "vertical" 時,在可繪製對象的頂部裁剪。 |
left | 將對象放在其容器左邊緣,不改變其大小。這是默認值。當 clipOrientation 是 "horizontal" 時,在可繪製對象的右邊裁剪。這是默認值。 |
right | 將對象放在其容器右邊緣,不改變其大小。當 clipOrientation 是 "horizontal" 時,在可繪製對象的左邊裁剪。 |
center_vertical | 將對象放在其容器的垂直中心,不改變其大小。裁剪行爲與重力爲 "center" 時相同。 |
fill_vertical | 按須要擴展對象的垂直大小,使其徹底適應其容器。當 clipOrientation 是 "vertical" 時,不會進行裁剪,由於可繪製對象會填充垂直空間(除非可繪製對象級別爲 0,此時它不可見)。 |
center_horizontal | 將對象放在其容器的水平中心,不改變其大小。裁剪行爲與重力爲 "center" 時相同。 |
fill_horizontal | 按須要擴展對象的水平大小,使其徹底適應其容器。當 clipOrientation 是 "horizontal" 時,不會進行裁剪,由於可繪製對象會填充水平空間(除非可繪製對象級別爲 0,此時它不可見)。 |
center | 將對象放在其容器的水平和垂直軸中心,不改變其大小。當 clipOrientation 是 "horizontal" 時,在左邊和右邊裁剪。當 clipOrientation 是 "vertical" 時,在頂部和底部裁剪。 |
fill | 按須要擴展對象的垂直大小,使其徹底適應其容器。不會進行裁剪,由於可繪製對象會填充水平和垂直空間(除非可繪製對象級別爲 0,此時它不可見)。 |
clip_vertical | 可設置爲讓子元素的上邊緣和/或下邊緣裁剪至其容器邊界的附加選項。裁剪基於垂直重力:頂部重力裁剪上邊緣,底部重力裁剪下邊緣,任一重力不會同時裁剪兩邊。 |
clip_horizontal | 可設置爲讓子元素的左邊和/或右邊裁剪至其容器邊界的附加選項。裁剪基於水平重力:左邊重力裁剪右邊緣,右邊重力裁剪左邊緣,任一重力不會同時裁剪兩邊。 |
定義
<?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}")
}
}
}
複製代碼
效果圖
與 ScaleDrawable 和 ClipDrawable 相似,RotateDrawable 能夠根據 level 值將 Drawable 進行動態旋轉。
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" />
複製代碼
它的根標籤爲 <clip>,各個屬性的含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現有的的 Drawable |
android:visible | 是否可見 |
android:fromDegrees | 旋轉起始角度 |
android:toDegrees | 旋轉結束角度 |
android:pivotX | 旋轉中心位於 X 軸的百分比 |
android:pivotY | 旋轉中心位於 Y 軸的百分比 |
下面以定義一個可旋轉的背景爲例展現 RotateDrawable 的簡單使用
定義
<?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}")
}
}
}
複製代碼
效果圖
有時候咱們可能須要在兩個圖片切換的時候增長漸變效果,除了使用動畫以外,這裏還能夠用 TransitionDrawable 輕鬆實現。
<?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>
複製代碼
它的根標籤爲 <transition>,它能夠包含多個 <item> 標籤,每一個 item 表示一個 Drawable,item 的屬性含義分別是:
屬性 | 含義 |
---|---|
android:drawable | drawable 資源,可引用現有的的 Drawable |
android:id | iitem 的 id,使用"@+id/name"的形式表示。可經過 View.findViewById() 或者 Activity.findViewById() 方法查找到這個 Drawable |
android:top、android:right、android:bottom、android:left | Drawable 相對於 View 在各個方向的偏移量 |
這裏定義一個淡入淡出效果的圖片切換效果,展現 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) {
}
})
}
複製代碼
效果圖
好了,傳統的 Drawable 就介紹完了,可是隨着 Android 版本的更新,Drawable 家族也不斷得有新成員加入進來,讓開發者有了更多的選擇,下一部分文章,我將介紹從 Android 5.0(API 21) 以後加入進來的幾個成員。
附:文章中的 Demo 地址:github.com/guanpj/Draw…