Android 這些 Drawable 你都會用嗎?Part1

1. 概述

在實際開發的過程當中,除了廣爲人知的利用 StateListDrawable 設置按鈕點擊特效,咱們有時可能會接到一些這樣的需求,好比要求咱們的頭像顯示成圓形或者圓角矩形,甚至要加上可變顏色的邊框,或者要求你作一套啓動、暫停、快進和快退的視頻控制按鈕而且能夠改變按鈕圖標顏色。可能某些時候第一反應就是用自定義 View 來實現,可是若是熟悉了 Drawable 的用法以後,這些效果一樣能夠利用它來完成,而選擇哪一種 Drawable 來實現也大有講究。php

Google 官方文檔中列出了各類各類各樣的 Drawable,那麼它們都是如何使用的呢?html

google-docs-drawable

本系列文章將分爲兩個部分,介紹其中大部分 Drawable 的用法。android

2. BitmapDrawable

BitmapDrawable 能夠看做是對 Bitmap 的一種包裝,它能夠設定 Bitmap 的顯示方式、位置等屬性。git

2.1 語法

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:水平和垂直方向交替鏡像進行重複繪製

2.2 用法示例

下面以定義一個使用圖片做爲背景的 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

bitmap-drawable

3. ShapeDrawable 和 GradientDrawable

官方文檔中對 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 a RectShape.

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。

3.1 語法

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,不然沒法顯示虛線效果。

3.2 用法示例

下面以定義一個圓角並帶有其餘效果的 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>
複製代碼

效果圖

gradient-drawable

4. StateListDrawable

StateListDrawable 能夠根據對象的狀態並使用不一樣的 item(Drawable) 對象來表示同一個圖形。如能夠根據 Button 的狀態(按下、獲取焦點等)來顯示不一樣的 Drawable 從而實現點擊的效果。

4.1 語法

定義 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:enterFadeDurationandroid: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 是否窗口已獲得焦點狀態

4.2 用法示例

下面以定製一個具備點擊效果 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>
複製代碼

效果圖

state-list-drawable

5. LayerDrawable

LayerDrawable 是管理 Drawable 列表的 Drawable。列表中的每一個 item 按照列表的順序繪製,列表中的最後 item 繪於頂部。

5.1 語法

定義 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 尺寸小於容器尺寸時在容器中的擺放位置

5.2 用法示例

下面以定義一個圓角並帶陰影效果的 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>
複製代碼

效果圖

gradient-drawable

6. LevelListDrawable

LevelListDrawable 一樣表示一個 Drawable 列表,列表中的每一個 item 都有一個 level 值, LevelListDrawable 會根據不一樣的 level 在不一樣的 item 之間進行切換。

6.1 語法

定義 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]

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) }
        }
    }
}
複製代碼

效果圖

level-list-drawable

7. InsetDrawable

在有些場景下,咱們可能須要設置一個全屏的背景圖片,但又想讓背景圖片跟邊框留出一些間隙,這時使用 InsetDrawable 就能很好地解決問題了。

7.1 語法

<?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 內容距離各個邊框的距離

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>
複製代碼

效果圖

inset-drawable

8. ScaleDrawable

ScaleDrawable 能夠根據 level 值動態地將 Drawable 進行必定比例的縮放。當 level 的取值範圍爲 [0, 10000],當 level 爲 0 時表示隱藏;當 level 值爲 1 時,Drawable 的大小爲初始化時的縮放比例,當 level 值爲 10000 時,Drawable 大小爲 100% 縮放比例。

8.1 語法

定義 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 寬的縮放比例

8.2 用法示例

這裏採用定製一個大小可變的背景爲例,展現 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}")
            }
    }
}
複製代碼

效果圖

scale-drawable

9. ClipDrawable

與 ScaleDrawable 原理相同,ClipDrawable 則能夠根據 level 值動態地將 Drawable 進行必定比例的剪裁。當 level 的取值範圍爲 [0, 10000],當 level 爲 0 時表示隱藏;當 level 值爲 1 時,Drawable 的大小爲初始化時的剪裁比例,當 level 值爲 10000 時,Drawable 大小爲 100% 剪裁比例。

9.1 語法

定義 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 可設置爲讓子元素的左邊和/或右邊裁剪至其容器邊界的附加選項。裁剪基於水平重力:左邊重力裁剪右邊緣,右邊重力裁剪左邊緣,任一重力不會同時裁剪兩邊。

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}")
            }
    }
}
複製代碼

效果圖

clip-drawable

10. RotateDrawable

與 ScaleDrawable 和 ClipDrawable 相似,RotateDrawable 能夠根據 level 值將 Drawable 進行動態旋轉。

10.1 語法

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 軸的百分比

10.2 用法示例

下面以定義一個可旋轉的背景爲例展現 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}")
            }
    }
}

複製代碼

效果圖

rotate-drawable

11. TransitionDrawable

有時候咱們可能須要在兩個圖片切換的時候增長漸變效果,除了使用動畫以外,這裏還能夠用 TransitionDrawable 輕鬆實現。

11.1 語法

<?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 在各個方向的偏移量

11.2 用法示例

這裏定義一個淡入淡出效果的圖片切換效果,展現 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) {
                }

            })
    }

複製代碼

效果圖

transition-drawable

好了,傳統的 Drawable 就介紹完了,可是隨着 Android 版本的更新,Drawable 家族也不斷得有新成員加入進來,讓開發者有了更多的選擇,下一部分文章,我將介紹從 Android 5.0(API 21) 以後加入進來的幾個成員。

附:文章中的 Demo 地址:github.com/guanpj/Draw…

相關文章
相關標籤/搜索