1. BitmapDrawable 概述
BitmapDrawable 几乎是最简单的 Drawable,表示的就是一张图片
在实际开发中 ,可以直接引用原始的图片,也可以通过 XML 的
标签 的方式来描述一个 BitmapDrawable,通过 XML 描述可以设置更多的效果,语法如下:1
2
3
4
5
6
7
8
9
10
11
12<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schema.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:src
图片的资源 id android:antialias
是否开启图片抗锯齿功能。开启后会让图片变得平滑,同时也会在一定程度上降低图片的清晰度,但是这个降低的清晰度的幅度较低以至于可以忽略,因此抗锯齿选项应该开启 android:dither
是否开启抖动效果。当图片的像素配置和手机屏幕的像素配置不一致时,开启这个选项可以让高质量的图片在低质量的屏幕上还能保持较好的显示效果,比如图片的色彩模式为 ARGB8888,但是设备屏幕所支持的色彩模式为 RGB555,这个时候开启抖动模式可以让图片显示不会过于失真。在 Android 中创建 Bitmap 一般会选用 ARGB8888 这个模式,即 ARGB 四个通道各占 8 位,在这种色彩模式下,一个像素所占的大小为 4 个字节,一个像素的位数总和越高,图片也就越逼真。综上,抖动效果也应该开启 android:filter
是否开启过滤效果。当图片尺寸被拉伸或者压缩时,开启过滤效果可以保持较好的显示效果,因此也应该开启 android:gravity
当图片小于容器的尺寸时,设置此选项可以对图片进行定位。这个属性的可选性比较多,不同的选项可以通过 “ android:mipMap
这是一种图像相关的处理技术,也叫纹理映射,比较抽象,这里就不深究了,默认值为 false,在日常开发中不常用 android:tileMode
平铺模式。这个选项有如下几个值:”disabled”、”clamp”、”repeat”、”mirror”,其中 disable 表示关闭平铺模式,false 也是默认值,当开启平铺模式后,gravity 属性会被忽略。这里主要说一下 repeat、mirror 和 clamp 的区别,这三者都表示平铺模式,但是他们的表现却有很大不同。repeat 表示的是简单的水平和竖直方向上的平铺效果;mirror 表示一种在水平和竖直方向上的镜面投影效果;clamp 表示的效果就更加奇特,图片四周的像素会扩展到周围区域 gravity 属性的可选项
可选项 含义 top
将图片放在容器的顶部,不改变图片的大小 bottom
将图片放在容器的底部,不改变图片的大小 left
将图片放在容器的左部,不改变图片的大小 right
将图片放在容器的右部,不改变图片的大小 center_vertical
使图片竖直居中,不改变图片的大小 center_horizontal
使图片水平居中,不改变图片的大小 fill_vertical
图片竖直方向填充容器 fill_horizontal
图片水平方向填充容器 center
使图片在水平和竖直方向同时居中,不改变图片的大小 fill
图片在水平和竖直方向均填充容器,这是默认值 clip_vertical
附加选项,表示竖直方向的裁剪,较少使用 clip_horizontal
附加选项,表示水平方向的裁剪,较少使用 tileMode 几种平铺模式下的图片显示效果
NinePatchDrawable 概述
NinePatchDrawable 表示的是一种 .9 格式的图片,.9 图片可以自动根据所需的宽高进行相应的缩放并保证不失真
在实际使用中直接引用图片即可,也可以通过 XML 的 nine-patch 标签 来描述 .9 图:
1
2
3
4
5
<nine-patch
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@[package:] drawable/drawable_resource"
android:dither=["true" | "false"] />在实际使用中发现在 bitmap 标签中也可以使用 .9 图,即 BitmapDrawable 也可以代表一个 .9 格式的图片
2. ShapeDrawable 概述
ShapeDrawable 是一种很常见的 Drawable,可以理解为通过颜色来构造的图形,既可以是纯色的图形,也可以是具有渐变效果的图形
ShapeDrawable 的语法:
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
<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:bottomLeftRadisu="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:useLevel=["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>标签
<shape>
创建的 Drawable,实体类实际上是 GradientDrawableandroid:shape
: 表示图形的形状,有四个选项:rectangle
(矩形)、oval
(椭圆)、line
(横线)、ring
(圆环)。它的默认值是矩形,另外line
和ring
这两个选项必须要通过<stroke>
标签来指定线的宽度和颜色等信息,否则将无法达到预期的显示效果。其中,ring
有五个特殊的属性值,如下表:属性 含义 android:innerRadius
圆环的内半径,和 android:innerRadiusRatio
同时存在时,以前者为准android:thickness
圆环的厚度,即外半径减去内半径的大小,和 android:thicknessRatio
同时存在时,以前者为准android:innerRadiusRatio
内半径占整个 Drawable 宽度的比例,默认值为 9。如果为 n,那么内半径 = 宽度 / n android:thicknessRatio
厚度占整个 Drawable 宽度的比例,默认值为 3。如果为 n,那么厚度 = 宽度 / n android:useLevel
一般都应该使用 false,否则有可能无法达到预期的显示效果,除非被当作 LevelListDrawable 来使用 <corners>
: 表示 shape 的四个角的角度,只适用于矩形 shape。这里的角度是指圆角的程度,用 px 表示,属性值如下表:属性 含义 android:radius
为四个角同时设定相同的角度,优先级较低,会被其他四个属性覆盖 android:topLeftRadius
设定左上角的角度 android:topRightRadius
设定右上角的角度 android:bottomLeftRadius
设定左下角的角度 android:bottomRightRadius
设定右下角的角度 <gradient>
: 注意与<solid>
标签是互相排斥的,其中 solid 表示纯色填充,而 gradient 表示渐变效果。属性值如下表:属性 含义 android:angle
渐变的角度,默认为 0,其值必须为 45 的倍数,0 表示从左到右,90 表示从下到上,角度会影响渐变的方向 android:centerX
渐变的中心点的横坐标 android:centerY
渐变的中心点的纵坐标 android:startColor
渐变的起始色 android:centerColor
渐变的中间色 android:endColor
渐变的结束色 android:gradientRadius
渐变半径,仅当 android:type="radial"
时有效android:useLevel
一般为 false,当 Drawable 作为 StateListDrawable
使用时为 trueandroid:type
渐变的类别,有 linear 线性渐变、radial 径向渐变、sweep 扫描线渐变 三种,默认为线性渐变 <solid>
: 表示纯色填充,通过android:color
指定 shape 中填充的颜色<stroke>
: shape 的描边,属性值如下表:属性 含义 android:width
描边的宽度 android:color
描边的颜色 android:dashWidth
组成虚线的线段的宽度 android:dashGap
组成虚线的线段之间的间隔 - 如果
android:dashWidth
和android:dashGap
有任何一个为 0,那么虚线效果将不能生效
- 如果
<padding>
: 表示空白,但是它表示的不是 shape 的空白,而是包含它的 View 的空白,有四个属性:android:left
、android:top
、android:right
和android:bottom
<size>
: shape 的大小,两个属性:android:width
和android:height
分别表示 shape 的宽高。这个表示的是 shape 的固有大小,但是一般来说它并不是 shape 最终显示的大小,实际上对于 shape 来说他并没有宽高的概念,作为 view 的背景它会自适应 View 的宽高。Drawable 的两个方法getIntrinsicWidth()
和getIntrinsicHeight()
表示的是 Drawable 的固有宽高,对于有些 Drawable 比如图片来说,它的固有宽高就是图片的尺寸。而对于 shape 来说,默认情况下它是没有固有宽高这个概念的,此时getIntrinsicWidth()
和getIntrinsicHeight()
会返回 -1,但是如果通过<size>
标签来指定宽高信息,那这个时候 shape 就有了所谓的宽高。因此,总结来说,<size>
标签设置的宽高就是 ShapeDrawable 的固有宽高,但是作为 View 的背景时,shape 还会被拉伸或者缩小为 View 的大小
3. LayerDrawable 概述
LayerDrawable 对应的 XML 标签是
<layer-list>
,它表示一种层次化的 Drawable 集合,通过将不同的 Drawable 放置在不同的层上面从而达到一种叠加后的效果,语法如下:1
2
3
4
5
6
7
8
9
10
11
<layer-list
xmlns:android="http://shcemas.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" />
</layer-list>一个 layer-list 中可以包含多个 item,每个 item 表示一个 Drawable
常用的属性
android:top
、android:bottom
、android:left
和android:right
分别表示 Drawable 相对于 View 的上下左右的偏移量,单位为像素默认情况下,layer-list 中的所有的 Drawable 都会被缩放至 View 的大小,对于 bitmap 来说,需要使用 android:gravity 属性才能控制图片的显示效果
layer-list 有层次的概念,下面的 item 会覆盖上面的 item,通过合理的分层,可以实现一些特殊的叠加效果
4. StateListDrawable
StateListDrawable 对应于
<selector>
标签,也是表示 Drawable 集合,每个 Drawable 都对应着 View 的一种状态,这样系统就会根据 View 的状态选择合适的 DrawableStateListDrawable 主要用于设置可单击的 View 的背景,最常见的是 Button,语法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<?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"] >
<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=["true" | "false"] />
</selector>StateListDrawable 各个属性的含义
属性 含义 android:constantSize
StateListDrawable 的固有大小是否不随着其状态的改变而改变,因为状态的改变会导致 StateListDrawable 切换到具体的 Drawable,而不同的 Drawable 具有不同的固有大小。True 表示 StateListDrawable 的固有大小保持不变,这时它的固有大小是内部所有 Drawable 的固有大小的最大值,false 则会随着状态的改变而改变,默认值为 false android:dither
是否开启抖动效果,这个在 BitmapDrawable 中也有提到,开启此选项可以让图片在低质量的屏幕上仍然获得较好的显示效果,默认值为 true android:variablePadding
StateListDrawable 的 padding 表示是否随着其状态的改变而改变,true 表示会随着状态的改变而改变,false 表示 StateListDrawable 的 padding 是内部所有 Drawable 的 padding 的最大值。默认值为 false,并且不建议开启此选项 <item>
标签表示一个具体的 Drawable,其中 android:drawable
是一个已有 Drawable 的资源 id,剩下的属性表示的是 View 的各种状态,每个 item 表示的都是一种状态下的 Drawable 信息View 的常见状态
状态 含义 android:state_pressed
表示按下状态,比如 Button 被按下后仍没有松开时的状态 android:state_focused
表示 View 已经获取了焦点 android:state_selected
表示用户选择了 View android:state_checked
表示用户选中了 View,一般适用于 CheckBox 这类在选中和非选中状态之间进行切换的 View android:state_enabled
表示 View 当前处于可用状态 Demo:
1
2
3
4
5
6
7
8
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/button_pressed" /> <!-- pressed -->
<item android:state_focused="true"
android:drawable="@drawable/button_focused" /> <!-- focused -->
<item android:drawable="@drawable/button_normal" /> <!-- default -->
</selector>- 系统会根据 View 当前的状态从 selector 中选中对应的 item,每个 item 对应着一个具体的 Drawable,系统按照从上到下的顺序查找,直至查找到第一条匹配的 item
- 一般来说,默认的 item 都应该放在 selector 的最后一条并且不附带任何的状态,这样当上面的 item 都无法匹配 View 当前状态时,系统就会选择默认的 item,因为默认的 item 不附带状态,所以它可以匹配 View 的任何状态
5. LevelListDrawable
LevelListDrawable 对应于
<level-list>
标签,同样表示一个 Drawable 集合,集合中的每个 Drawable 都有一个等级(level)的概念根据不同的等级,LevelListDrawable 会切换为对应的 Drawable,语法如下:
1
2
3
4
5
6
7
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>- 每个 item 表示一个 Drawable,并且有对应的等级范围,由
android:minLevel
和android:maxLevel
来指定,在最小值和最大值之间的等级会对应此 item 中的 Drawable - 当作为 View 背景时,可以通过 Drawable 的
setLevel()
方法来设置不同的等级从而切换具体的 Drawable - 当作为 ImageView 的前景 Drawable 时,可以通过 ImageView 的
setImageLevel()
方法来切换 Drawable - Drawable 的等级是有范围的,即 0 ~ 10000,最小等级是 0(默认值),最大等级是 10000
- 每个 item 表示一个 Drawable,并且有对应的等级范围,由
Demo:
1
2
3
4
5
6
7
8
9
<level-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:drawable="@drawable/status_off"
android:maxLevel="0" />
<item
android:drawable="@drawable/status_on"
android:maxLevel="1" />
</level-list>
6. TransitionDrawable
TransitionDrawable 对应于
<transition>
标签,用于实现两个 Drawable 之间的淡入淡出的效果,语法如下:1
2
3
4
5
6
7
8
9
10
<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>android:top
、android:bottom
、android:left
和android:right
仍然表示的是 Drawable 四周的偏移量
Demo:
1
2
3
4
5
6// 定义 TransitionDrawable
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/drawable1" />
<item android:drawable="@drawable/drawable2" />
</transition>1
2
3
4
5
6// 使用 TransitionDrawable
<TextView
android:id="@+id/button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:backgroud="@drawable/transition_drawable" />1
2
3
4// 实现淡入淡出及其逆过程
Textview textView = (TextView) findViewById(R.id.test_transition);
TransitionDrawable transitionDrawable = (TransitionDrawable) textView.getBackground();
transitionDrawable.startTransition(1000); // reverseTransition();
7. InsetDrawable
InsetDrawable 对应于
<inset>
标签,它可以将其他 Drawable 内嵌到自己当中,并可以在四周留出一定的间距当一个 View 希望自己的背景比自己的实际区域小的时候,可以采用 InsetDrawable 来实现。同时,通过 LayerDrawable 也可以实现这种效果,语法如下:
1
2
3
4
5
6
7
8
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:insetTop="dimension"
android:insetRight="dimension"
androd:insetBottom="dimension"
android:insetLeft="dimension" />android:insetTop
、android:insetBottom
、android:insetLeft
和android:insetRight
分别表示顶部、底部、左边和右边内凹的大小
Demo:
1
2
3
4
5
6
7
8
9
10
11
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetBottom="15dp"
android:insetLeft="15dp"
android:insetRight="15dp"
android:insetTop="15dp" >
<shape android:shape="rectangle" >
<solid android:color="#ff0000" />
</shape>
</inset>
8. ScaleDrawable
ScaleDrawable 对应于
<scale>
标签,它可以根据自己的等级(level)将指定的 Drawable 缩放到一定比例,语法如下: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" />android:scaleGravity
的含义等同于 shape 中的androdi:gravity
,android:scaleWidth
和android:scaleHeight
分别表示对指定 Drawable 的宽和高的缩放比例,以百分比的形式表示- 等级 0 是默认值,表示不可见;等级 10000 是最大值,表示没有缩放效果。如果 ScaleDrawable 的级别(level)越大,那么内部的 Drawable 看起来就越大。如果 ScaleDrawable 的 XML 中所定义的缩放比例越大,那么内部的 Drawable 看起来就越小
Demo:
1
2
3
4
5
6
7// 近似地将一张图片缩小为原大小的 30%
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/image1"
android:scaleHeight="70%"
android:scaleWidth="70%"
android:scaleGravity="center" />1
2
3
4// 直接使用上面的 drawable 资源是不行的,还必须设置 ScaleDrawable 的等级(level)为大于 0 且小于 10000 的值。否则,由于 Drawable 的默认等级是 0,那么 ScaleDrawable 将无法显示出来
View view = findViewById(R.id.test_scale);
ScaleDrawable scaleDrawable = (ScaleDrawable) view.getBackground();
scaleDrawable.setLevel(1);
9. ClipDrawable
ClipDrawable 对应于
<clip>
标签,它可以根据自己当前的等级(level)来裁剪另一个 Drawable。裁剪方向可以通过android:clipOrientation
和android:gravity
这两个属性来共同控制,语法如下:1
2
3
4
5
6
7
8<?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_vertival" | "center_horizontal" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"] />- clipOrientation 表示裁剪方向,有水平和竖直两个方向。gravity 比较复杂,需要和 clipOrientation 一起才能发挥作用
ClipDrawable 的 gravity 属性含义
属性值 含义 top
将内部的 Drawable 放在容器的顶部,不改变它的大小。如果为竖直裁剪,那么从底部开始裁剪 bottom
将内部的 Drawable 放在容器的底部,不改变它的大小。如果为竖直裁剪,那么从顶部开始裁剪 left
将内部的 Drawable 放在容器的左边,不改变它的大小。如果为水平裁剪,那么从右边开始裁剪,这是默认值 right
将内部的 Drawable 放在容器的右边,不改变它的大小。如果为水平裁剪,那么从左边开始裁剪 center_vertical
将内部的 Drawable 放在容器中竖直居中,不改变它的大小。如果为竖直裁剪,那么从上下同时开始裁剪 fill_vertical
将内部的 Drawable 在竖直方向上填充容器。如果为竖直裁剪,那么仅当 ClipDrawable 的等级为 0(0 表示 ClipDrawable 被完全裁剪,即不可见)时,才能有裁剪行为 center_horizontal
使内部的 Drawable 在容器中水平居中,不改变它的大小。如果为水平裁剪,那么从左右两边同时开始裁剪 fill_horizontal
使内部的 Drawable 在水平方向上填充容器。如果为水平裁剪,那么仅当 ClipDrawable 的等级为 0 时,才能有裁剪行为 center
使内部的 Drawable 在容器中水平和竖直方向都居中,不改变它的大小。如果为竖直裁剪,那么从上下同时开始裁剪;如果为水平裁剪,那么从左右同时开始裁剪 fill
使内部的 Drawable 在水平和竖直方向上同时填充容器。仅当 ClipDrawable 的等级为 0 时,才能有裁剪行为 clip_vertical
附近选项,表示竖直方向的裁剪,较少使用 clip_horizontal
附近选项,表示水平方向的裁剪,较少使用 Demo:
1
2
3
4
5
6// 定义 ClipDrawable,实现顶部裁剪的效果
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/image1"
android:clipOrientation="vertical"
android:gravity="bottom" />1
2
3
4
5
6
7// 设置 ClipDrawable
<ImageView
android:id="@+id/test_clip"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/clip_drawable"
android:gravity="center" />1
2
3
4// 使用 ClipDrawable,设置 ClipDrawable 的等级
ImageView imageView = (ImageView) findViewById(R.id.test_clip);
ClipDrawable clipDrawable = (ClipDrawable) imageView.getDrawable();
clipDrawable.setLevel(8000); // 表示裁剪 2000,即在顶部裁减掉 20% 的区域,被裁剪的区域就相当于不存在了- Drawable 的等级(level)是有范围的,即 0 ~ 10000,最小等级是 0,最大等级是 10000
- 对于 ClipDrawable 来说,等级 0 表示完全裁剪,即整个 Drawable 都不可见了,等级 10000 表示不裁剪,等级越大裁剪掉的区域越小