Android 這些 Drawable 你都會(huì)用嗎?Part1

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,那么它們都是如何使用的呢?

google-docs-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>

效果圖

bitmap-drawable

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 a RectShape.

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>

效果圖

gradient-drawable

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:enterFadeDurationandroid: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>

效果圖

state-list-drawable

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>

效果圖

gradient-drawable

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) }
        }
    }
}

效果圖

level-list-drawable

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>

效果圖

inset-drawable

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}")
            }
    }
}

效果圖

scale-drawable

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}")
            }
    }
}

效果圖

clip-drawable

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}")
            }
    }
}

效果圖

rotate-drawable

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) {
                }

            })
    }

效果圖

transition-drawable

好了,傳統(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,185評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 175,656評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,647評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,446評(píng)論 6 405
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 54,951評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,189評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,718評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,800評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,419評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,671評(píng)論 1 281
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,420評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,755評(píng)論 2 371

推薦閱讀更多精彩內(nèi)容