文章

系统提供Drawable

系统提供Drawable

ShapeDrawable 和 GradientDrawable

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.

ShapeDrawable 是一个用来绘制原始形状的 Drawable 对象。

GradientDrawable

A Drawable with a color gradient for buttons, backgrounds, etc.
It can be defined in an XML file with the  element. For more information, see the guide to Drawable Resources.

GradientDrawable 它是一个具有色彩梯度(color gradient)的 Drawable。

shape/gradient xml 语法

GradientDrawable 和 ShapeDrawable 都采用 shape 标签来定义,和 ShapeDrawable 最大的不同的就是它拥有 gradient 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?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 的时候,还有一下几个属性可配置:

圆角半径

1
2
3
4
5
6
<corners
    android:radius="integer"
    android:topLeftRadius="integer"
    android:topRightRadius="integer"
    android:bottomLeftRadius="integer"
    android:bottomRightRadius="integer" />

指图形的圆角半径,仅当 shape 属性为 rectangle 即形状是矩形时生效,数值越小越接近直角,android:radius 同时设置四个角的半径,其他四个属性则可单独设置某个角的半径。

渐变属性

1
2
3
4
5
6
7
8
9
10
<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"] />

表示颜色渐变,它的各个属性值的含义分别是:

Radial GradientDrawable 兼容问题

设置 android:gradientRadius 属性值时:

  • Api 21 以下:只能使用 Float 格式数据。%、%p、dimension 格式没有预期效果;
  • Api 21 时:只能使用 Fraction(%,%p)、Dimension 格式数据。不能使用 Float 数据,否则 Float 会被解析为 Dimension,显示错误。drawable 自身 size 未指定时,使用% 格式不会显示;
  • Api 22 及以上:可以正常使用 Float、Dimension、%、%p 格式。

内边距

距离内容或者子元素的内边距,每个方向可以单独设置。

shape 大小

设置 shape 大小,width 表示宽度,height 表示高度。需要注意的是,这个一般并不是 shape 的最终大小,如果用作 View 的背景,它的大小是由 View 的大小来决定的。

填充颜色

表示纯色填充,color 属性为填充的颜色。

边框

边框描述,它的各个属性值的含义分别是:

需要注意的是,如果需要设置边框虚线效果,则需要同时设置 dashWidth 和 dashGap 的值不为 0,否则无法显示虚线效果。

gradient 标签

<gradient> 标签它与 <solid> 标签是互相排斥的,其中 solid 表示纯色填充,而 gradient 则表示渐变效果。

gradient xml 属性介绍

1
2
3
4
5
6
7
8
9
10
<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:useLevel=["true" | "false"] />

* android:type

  • linear : 线性渐变
  • radial:A radial gradient. 放射性渐变(圆形渐变),起始颜色从 centerX, centerY 点开始。
  • sweep:A sweeping line gradient. 扫描式渐变(扇形渐变)。

* android:angle

Integer,代表渐变颜色的角度, 0 is left to right, 90 is bottom to top. 必须是 45 的整数倍. 默认是 0.该属性只有在 type=linear 情况下起作用,默认的 type 为 linear。

* android:startColor

颜色渐变的开始颜色

* android:endColor

颜色渐变的结束颜色

* android:centerColor

颜色渐变的中间颜色

* android:centerX

Float.(0 - 1.0) 相对 X 的渐变位置。

* android:centerY

Float.(0 - 1.0) 相对 Y 的渐变位置。

centerX 和 centerY,这两个属性只有在 android:type 不为 linear 情况下起作用。

* android:gradientRadius

Float. 渐变颜色的半径,单位应该是像素点。需要 android:type="radial"

如果 android:type=”radial”,没有设置 android:gradientRadius,将会报错,error inflating class。

* android:useLevel

使用 LevelListDrawable 时就要设置为 true,设为 false 时才有渐变效果。

gradient 颜色渐变方向

1
2
3
4
当angle为0时,颜色渐变方向是从左往右;
当angle为90时,颜色渐变方向是从下往上;
当angle为180时,颜色渐变方向是从右往左;
当angle为270时,颜色渐变方向是从上往下;

默认方向是从左往右,逆时针;Android10.0 系统发现渐变方向是从上往下,需要加上 android:angle=”0”

示例:从上到下,粉色渐变到白色

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:shape="rectangle"
    android:useLevel="false"
    tools:ignore="ResourceName">

    <gradient
        android:angle="270"
        android:endColor="#FFFFFF"
        android:startColor="#FFECE4" />
</shape>

image.png

gradient 代码设置 - GradientDrawable

GradientDrawable 颜色渐变相关的方法

setGradientType(@GradientType int gradient)

setGradientType 对应 gradient 标签 android:type 属性,对应的值有:LINEAR_GRADIENT,RADIAL_GRADIENT,SWEEP_GRADIENT;分别是:线性渐变,放射性渐变,扫描式渐变。

setColor
1
2
3
setColor(@ColorInt int argb)
setColors(@ColorInt int[] colors)
setColor(@Nullable ColorStateList colorStateList)

setColors 设置渐变的颜色,包含一种,至少两种颜色等。对应 gradient 标签 android:startColor、android:centerColor 和 android:endColor; 但是 java 方法好像更加灵活,可以放多于三种颜色。

setOrientation(Orientation orientation)

setOrientation 设置线性渐变的方向。对应 gradient 标签 android:angle,可以取的值有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * 控制渐变相对于可绘制边界的方向
 */
public enum Orientation {
    /**
     * 从顶部到底部绘制渐变
     */
    TOP_BOTTOM,
    /**
     * 绘制从右上角到左下角的渐变
     */
    TR_BL,
    /**
     * 从右到左绘制渐变
     */
    RIGHT_LEFT,
    /**
     * 从右下角到左上角绘制渐变
     */
    BR_TL,
    /**
     * 从底部到顶部绘制渐变
     */
    BOTTOM_TOP,
    /**
     * 从左下角到右上角绘制渐变
     */
    BL_TR,
    /**
     * 从左到右绘制渐变
     */
    LEFT_RIGHT,
    /**
     * 绘制从左上角到右下角的渐变
     */
    TL_BR,
}
setGradientRadius(float gradientRadius)

setGradientRadius 设置渐变的半径。,只有当渐变类型设置为{RADIAL_GRADIENT}时,半径才有效。对应 gradient 标签 android:gradientRadius。

setCornerRadii(float[] radii) 设置四个角的圆角半径

数组分别指定四个圆角的半径,每个角可以指定 [X_Radius,Y_Radius],四个圆角的顺序为左上,右上,右下,左下。如果 X_Radius,Y_Radius 为 0 表示还是直角

1
drawable?.cornerRadii = floatArrayOf(radius, radius, radius, radius, 0f, 0f, 0f, 0f)

LayerDrawable

LayerDrawable 是管理 Drawable 列表的 Drawable。列表中的每个 item 按照列表的顺序绘制,列表中的最后 item 绘于顶部。根标签用 <layer-list> 表示,每一项用 <item> 表示。

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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 顶层标签为 ,它可以包含多个  标签,每个 item 表示一个 Drawable,item 的属性含义分别是:

![600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/1688144766728-4e237e0f-d95c-4766-aa52-7937ad9479a1.png)

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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/holo_green_dark" />
            <corners android:radius="10dp" />
        </shape>
    </item>

    <!--指定现有的 Drawable-->
    <item
        android:bottom="4dp"
        android:right="2dp">
        <shape>
            <gradient
                android:endColor="@color/white"
                android:startColor="@color/white" />
            <corners android:radius="4dp" />
        </shape>

    </item>

</layer-list>

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:background="@drawable/layer_list_shadow"
        android:orientation="vertical"
        android:padding="10dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:layout_editor_absoluteX="190dp"
        tools:layout_editor_absoluteY="331dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="I'm a title......."
            android:textColor="#000000"
            android:textSize="20sp" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="content content content content content content content content..."
            android:textColor="@android:color/darker_gray"
            android:textSize="16sp" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

效果:

![image.png300](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/1688144855664-9bf1255b-8e8f-4f6a-9591-44a2efb00d7b.png)

BitmapDrawable

语法

BitmapDrawable 对应 <bitmap> 标签定义,xml 语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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"] 
    android:autoMirrored="true" <!--api19及+可以--> />

其中各个属性的含义分别是:

![600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/1688144862748-6084ab26-095f-4031-a398-2779fdf91f3b.png)

案例

  1. repeat
1
2
3
4
5
6
7
8
<?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"/>
![600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/1688144949010-939962b8-f3ad-4414-b88a-9ba0ed50404b.png)
  1. autoMirrored,水平镜像(api19 及 + 可用)
1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:antialias="true"
    android:autoMirrored="true"
    android:dither="true"
    android:src="@drawable/ic_room_latest_head_bg" />

LevelListDrawable

LevelListDrawable 同样表示一个 Drawable 列表,列表中的每个 item 都有一个 level 值, LevelListDrawable 会根据不同的 level 在不同的 item 之间进行切换。

语法

1
2
3
4
5
6
7
8
<?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 根标签为 ,它可以包含多个  标签,每个 item 表示一个 Drawable,item 的属性含义分别是:

属性含义
android:drawabledrawable 资源,可引用现有的的 Drawable
android:maxLevel该 item 允许的最大级别,取值范围为 [0, 10000]
android:minLevel该 item 允许的最小级别,取值范围为 [0, 10000]

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/dice_one"
        android:maxLevel="0" />
    <item
        android:drawable="@drawable/dice_two"
        android:maxLevel="1" />
    <item
        android:drawable="@drawable/dice_three"
        android:maxLevel="2" />
    <item
        android:drawable="@drawable/dice_four"
        android:maxLevel="3" />
    <item
        android:drawable="@drawable/dice_five"
        android:maxLevel="4" />
    <item
        android:drawable="@drawable/dice_six"
        android:maxLevel="5" />
</level-list>

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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">

    <ImageView
        android:id="@+id/img"
        android:layout_width="230dp"
        android:layout_height="150dp"
        android:src="@drawable/level_list_demo"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

然后控制 ImageView 的 level 即可显示出效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class LevelListActivity : AppCompatActivity() {
    lateinit var mImageView: ImageView
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_level_list)

        mImageView = findViewById(R.id.img)
        for (i in 0..15) {
            mHandler.sendEmptyMessageDelayed(i, (1000 * i).toLong())
        }

    }
    private val mHandler: Handler = @SuppressLint("HandlerLeak")
    object : Handler() {
        override fun handleMessage(msg: Message?) {
            msg?.what?.let { mImageView.setImageLevel(it % 5) }
        }
    }
}

InsetDrawable

语法

1
2
3
4
5
6
7
8
<?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" />

根标签为 ,它的各个属性含义分别是:

属性含义
android:drawabledrawable 资源,可引用现有的的 Drawable
android:insetTop、android:insetRight、android:insetBottom、android:insetLeft内容距离各个边框的距离

案例

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/bg2"
    android:insetLeft="10dp"
    android:insetTop="20dp"
    android:insetRight="30dp"
    android:insetBottom="60dp" />

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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/inset_demo">

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="TextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextTextText"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

ScaleDrawable

ScaleDrawable 可以根据 level 值动态地将 Drawable 进行一定比例的缩放。当 level 的取值范围为 [0, 10000],当 level 为 0 时表示隐藏;当 level 值为 1 时,Drawable 的大小为初始化时的缩放比例,当 level 值为 10000 时,Drawable 大小为 100% 缩放比例。

语法

1
2
3
4
5
6
7
8
9
<?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:scaleHeight

Drawable 高的缩放比例,值越高最终结果越小。

android:scaleGravity

Drawable 宽的缩放比例

android:scaleGravity

当图片尺寸小于 View 时,设置这个属性值可以对图片进行定位,可以使用 | 符号组合使用,所有值的含义分别为:

![600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/1688145354435-fd62dae1-9b05-4e24-b64b-35494e7c16f6.png)

案例

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/bg2"
    android:scaleWidth="80%"
    android:scaleHeight="80%"
    android:scaleGravity="bottom" />

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:background="@drawable/scale_demo"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

代码使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class ScaleDrawableActivity : AppCompatActivity() {
    var curLevel = 0
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_scale_drawable)

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

ClipDrawable

与 ScaleDrawable 原理相同,ClipDrawable 则可以根据 level 值动态地将 Drawable 进行一定比例的剪裁。当 level 的取值范围为 [0, 10000],当 level 为 0 时表示隐藏;当 level 值为 1 时,Drawable 的大小为初始化时的剪裁比例,当 level 值为 10000 时,Drawable 大小为 100% 剪裁比例。

语法

1
2
3
4
5
6
7
<?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 来使用,可以使用 | 符号组合使用,所有值的含义分别为:

![600](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/1688145562600-d28230f5-5e04-4793-a94d-a4758a3e0fec.png)

案例

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="horizontal"
    android:drawable="@drawable/bg2"
    android:gravity="center" />

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:background="@drawable/clip_demo"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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}")
            }
    }
}

效果:
https://user-gold-cdn.xitu.io/2019/6/29/16ba291a4f1247bf?imageslim

RotateDrawable

与 ScaleDrawable 和 ClipDrawable 类似,RotateDrawable 可以根据 level 值将 Drawable 进行动态旋转。

语法

1
2
3
4
5
6
7
8
<?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" />

它的根标签为 <rotate>,各个属性的含义分别是:

image.png

案例

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/bg2"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="180" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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/rotate_demo"
        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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class RotateDrawableActivity : AppCompatActivity() {
    private 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
                    }
                }
    }
}

TransitionDrawable(transition)

在两个图片切换的时候增加渐变效果,除了使用动画之外,这里还可以用 TransitionDrawable 轻松实现。

1
2
3
4
5
6
7
8
9
10
11
<?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 的属性含义分别是:

image.png

案例

1
2
3
4
5
<?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>

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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>

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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) {
                }

            })
    }
}

Ref

RippleDrawable

StateListDrawable

StateListDrawable 可以根据对象的状态并使用不同的 item(Drawable) 对象来表示同一个图形。如可以根据 Button 的状态(按下、获取焦点等)来显示不同的 Drawable 从而实现点击的效果。

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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>

slector 标签

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 的属性含义分别是:

![500](undefined)
  1. android:state_pressed 设置是否按压状态,一般在 true 时设置该属性,表示已按压状态,默认为 false
  2. android:state_selected 设置是否选中状态,true 表示已选中,false 表示未选中
  3. android:state_checked 设置是否勾选状态,主要用于 CheckBox 和 RadioButton,true 表示已被勾选,false 表示未被勾选
  4. android:state_checkable 设置勾选是否可用状态,类似 state_enabled,只是 state_enabled 会影响触摸或点击事件,state_checkable 影响勾选事件
  5. android:state_focused 设置是否获得焦点状态,true 表示获得焦点,默认为 false,表示未获得焦点
  6. android:enabled
  7. android:state_activated 设置是否被激活状态,true 表示被激活,false 表示未激活,API Level 11 及以上才支持,可通过代码调用控件的 setActivated(boolean)
  8. android:state_window_focused 设置当前窗口是否获得焦点状态,true 表示获得焦点,false 表示未获得焦点,例如拉下通知栏或弹出对话框时,当前界面就会失去焦点;另外,ListView 的 ListItem 获得焦点时也会触发 true 状态,可以理解为当前窗口就是 ListItem

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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>

https://user-gold-cdn.xitu.io/2019/6/29/16ba291a1a930d5b?imageslim

TextView 字体 Color Selector

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/white" android:state_selected="true" />
    <item android:color="@color/transparent_50_percent_white" />
</selector>

自定义 Drawable

Ref

本文由作者按照 CC BY 4.0 进行授权