1 Drawable简介
-
在实际开发中,Drawable常被用来作为View的背景使用。
-
Drawable一般都是通过xml来定义,当然也可以用代码来创建具体的Drawable对象,只是用代码会稍显复杂。
-
Drawable的内部宽/高这个参数比较重要,通过getIntrinsicWidth和getIntrinsicHeight获取。
-
但并不是所有的Drawable都有内部宽/高:比如一张图片所形成的Drawable,它的内部宽/高就是图片的宽/高;
-
但是一个颜色所形成的Drawable就没有内部宽/高概念。
-
Drawable的内部宽/高不等同与它的大小,Drawable是没有大小概念的:当用作View的背景时,Drawable会被拉伸至View的同等大小。
-
2 Drawable分类
-
表示图片的Drawable:BitmapDrawable、NinePatchDrawable
-
颜色构造的Drawable:ShapeDrawable
-
图层叠加的Drawable:LayerDrawable
-
表示状态的Drawable:StateListDrawable
-
等级说明的Drawable:LevelListDrawable(根据level切换匹配的Drawable)、ScaleDrawable(根据level缩放比例Drawable)、ClipDrawable(根据level裁剪Drawable)
-
淡入淡出的Drawable:TransitionDrawable
-
内嵌的Drawable:InsetDrawable
2.1 BitmapDrawable
BitmapDrawable表示一张图片,在实际开发中,我们可以直接引用原始的图片即可,但也可以用xml定义的BitmapDrawable设置更多的效果。
<?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" | "center_horizontal" |
"fill_vertical" | "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:是否开启抖动效果。当图片的像素配置与手机屏幕的像素配置不一致时,开启这个选项可以让高质量的图片在低质量的屏幕上还能保持较好的显示效果。抖动效果应该开启。
-
android:filter:是否开启过滤效果。当图片尺寸被拉伸或者压缩时,开启过滤效果可以保持较好的显示效果。应该开启。
-
android:gravity:当图片小于容器的尺寸时,设置此选项可以对图片进行定位。
-
[“top” | bottom" | left" | “rigth”]:将图片放在容器的顶部/底部/左部/右部,不改变图片大小。
-
[“center_vertical” | “center_horizontal”]:将图片竖直/水平居中,不改变图片大小。
-
[“fill_vertial” | “fill_horizontal”]:图片竖直/水平方向填充容器。
-
[“center”]:使图片在水平和竖直方向同时居中,不改变图片大小。
-
[“fill”]:图片在水平和竖直方向均填充容器,这是默认值。
-
[“clip_vertical” | “clip_horizontal”]:附加选项,表示竖直/水平方向的裁剪,较少使用。
-
-
android:mipMap:纹理映射。默认值为false,不常用。
-
android:tileMode:平铺模式。默认disable关闭平铺模式,开启平铺模式后gravity属性会被忽略。
-
[“repeat”]:水平和竖直方向上的平铺效果。
-
[“mirror”]:在水平和竖直方向上的镜面投影效果。
-
[“clamp”]:图片四周的像素扩展到周围区域。
-
2.2 NinePatchDrawable
NinePatchDrawable表示一张.9格式图片,.9图片可以自动地根据所需的宽/高进行相应的缩放并保证不失真。
<?xml version="1.0" encoding="utf-8"?>
<nine-patch
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@[package:]drawable/drawable_resource"
android:dither=["ture" | "false"]/>
2.3 ShapeDrawable
ShapeDrawable是一种很常见的Drawable,可以理解为通过颜色来构造的图形,既可以是纯色的图形,也可以是具有
渐变效果的图形。<shape>
标签创建的Drawable,其实体类实际上是GradientDrawable。
<?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:startColor="color"
android:centerColor="color"
android:endColor="color"
android:gradientRadius="integer"
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>
以上属性说明:
-
android:shape:表示图形的形状,默认是rectangle矩形。rectangle(矩形)、oval(椭圆)、line(横线)、ring(圆环)。line和ring这两个选项必须要通过标签来指定线的宽度和颜色等信息。ring这个形状有5个特殊属性:
-
android:innerRadius:圆环内半径,和android:innerRadiusRatio同时存在时,以android:innerRadius为准。
-
android:innerRadiusRatio:内半径占整个Drawable宽度的比例,默认值为9。如果为n,那么内半径 = 宽度 / n。
-
android:thickness:圆环的厚度,即外半径减去内半径的大小,和android:thicknessRatio同时存在时,以android:thickness为准。
-
android:thicknessRatio:厚度占整个Drawable宽度的比例,默认值为3.如果为n,那么厚度 = 宽度 / n。
-
android:useLevel:一般应该使用false,否则有可能无法达到预期显示效果,除非它被当作LevelListDrawable使用。
-
-
<corners>
:表示shape四个角的角度,只适用于矩形rectangle。-
android:radius:为四个角同时设定相同的角度,优先级较低,会被其他四个属性覆盖。
-
android:topLeftRadius:设定左上角的角度。
-
android:topRightRadius:设定右上角的角度。
-
android:bottomLeftRadius:设定左下角的角度。
-
android:bottomRightRadius:设定右下角的角度。
-
-
<gradient>
:表示渐变效果,与标签互斥,solid表示纯色填充。-
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使用时为true。
-
android:type:渐变的类别,有linear(线性渐变)、radial(径向渐变)、sweep(扫描线渐变),默认为线性渐变。
-
-
<solid>
:表示纯色填充。 -
:shape的描边。
-
android:width:描边的宽度,越大则shape的边缘线越粗。
-
android:color:描边的颜色。
-
android:dashWidth:虚线的宽度。
-
android:dashGap:虚线之间的间隔,越大则虚线之间间隔越大。
【注:android:dashWidth和android:dashGap有任何一个为0,虚线效果不能生效】
-
-
<padding>
:表示空白,但不是表示shape的空白,而是包含它的View的空白。 -
<size>
:shape的大小。这里设置的是shape的固有宽/高,但作为View的背景时,shape还会被拉伸或缩小为View的大小。
2.4 LayerDrawable
LayerDrawable表示一种层次化的Drawable集合,每个 <item>
进行叠加的效果。
<?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:left="dimension"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"/>
..........
</layer-list>
举例:微信聊天文本输入框效果:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
<shape android:shape="rectangle">
<solid android:color="#0ac39e"/>
</shape>
</item>
<item android:bottom="6dp">
<shape android:shape="rectangle">
<solid android:color="#ffffff"/>
</shape>
</item>
<item
android:bottom="1dp"
android:left="1dp"
android:right="1dp">
<shape android:shape="rectangle">
<solid android:color="#ffffff"/>
</shape>
</item>
</layer-list>
2.5 StateListDrawable
StateListDrawable表示Drawable的集合,每个Drawable对应View的一种状态。
<?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:veriablePadding=["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_enabled=["true" | "false"]
android:state_activated=["true" | "false"]
andorid:state_window_focused=["true" | "false"]/>
</selector>
以上属性说明:
-
android:constantSize:状态的改变会导致StateListDrawable切换到具体的Drawable,不同的Drawable具有不同的固有大小。为true表示StateListDrawable的固有大小保持不变,这时它的固有大小是内部所有Drawable的固有大小的最大值。为false表示随着状态的改变而改变。默认为false。
-
android:dither:默认为true。可以让图片在低质量的屏幕上获得较好的显示效果。
-
android:veriablePadding:不建议开启此选项。为true表示StateListDrawable的padding会随着状态改变而改变。为false表示StateListDrawable的padding是内部所有Drawable的padding的最大值。默认值为false。
-
<item>
:-
android:state_pressed:表示按下状态。
-
android:state_focused:表示View获取了焦点。
-
android:state_selected:表示用户选择了View。
-
android:state_checked:表示用户选中了View,一般适用于CheckBox在选中和非选中状态之间进行切换的View。
-
android:state_enabled:表示View当前处于可用状态。
【注:系统会根据View当前的状态从上往下查找匹配的item,所以一般做法是把默认的item放在最后】
-
2.6 LevelListDrawable
LevelListDrawable表示一个Drawable集合,集合中的每个Drawable都有一个等级(level)概念,根据不同等级切换对应的Drawable。
<?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>
以上属性说明:
在android:minLevel和android:maxLevel之间指定的等级会匹配该Drawable。
等级范围0-10000,默认值为0。
举例:
-
作为View的背景,可以通过Drawable的setLevel方法来设置不同的等级切换具体的Drawable。
-
最为ImageView的前景,可以通过setImageLevel方法切换Drawable。
<?xml version="1.0 encoding="utf-8"?>
<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>
2.7 TransitionDrawable
TransitionDrawable用于实现两个Drawable之间的淡入淡出效果。
<?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:left="dimension"
android:top="dimension"
android:right="dimension"
android:bottom="dimension"/>
</transition>
TransitionDrawable的使用步骤:
- 定义一个TransitionDrawable:
<?xml verion="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/drawable1"/>
<item android:drawable="@drawable/drawable2"/>
</transition>
- 将上面的TransitionDrawable设置为View的背景:
<TextView
android:id="@+id/button"
android:layout_width="wrap_cotnent"
android:layout_height="wrap_content"
android:background="@drawable/transition_drawable"/>
- 通过startTransition和reverseTransition方法实现View的淡入淡出效果以及逆过程:
TextView textView = (TextView) findViewById(R.id.button);
TransitionDrawable drawable = (TransitionDrawable) textView.getBackground();
drawable.startTransition(1000);
2.8 InsetDrawable
InsetDrawable可以将其他Drawable内嵌到自己当中,并可以在四周留出一定的间距。
比如当一个View希望自己的背景比自己的实际区域小,可以采用InsetDrawable实现,也可以使用LayerDrawable实现。
<?xml version="1.0" encoding="utf-8"?>
<inset
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:insetLeft="dimension"
android:insetTop="dimension"
android:insetRight="dimension"
android:insetBottom="dimension"/>
以上属性说明:
insetLeft、insetTop、insetRight、insetBottom表示左边、顶部、右边、底部内凹的大小。
举例:inset中的shape距离View的边界为15dp
<?xml verion="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="15dp"
android:insetTop="15dp"
android:insetRight="15dp"
anroid:insetBottom="15dp">
<shape android:shape="rectangle">
<solid android:color="#ff0000"/>
</shape>
</inset>
2.9 ScaleDrawable
ScaleDrawable可以根据自己的等级(level)将指定的Drawable缩放到一定比例。默认等级为0,最大为10000。
<?xml version="1.0" encoding="utf-8"?>
<scale
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/drawable_resource"
android:scaleGravity=["left" | "top" | "right" | "bottom" |
"center_vertical" | "center_horizontal" | fill_vertical" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"]
android:scaleWidth="percentage"
android:scaleHeight="percentage"/>
以上属性说明:
android:scaleWidth和android:scaleHeight表示指定Drawable宽和高的缩放比例,百分比形式表示。
举例:一个图片缩小为原大小的30%:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/image1"
android:scaleWidth="70%"
android:scaleHeight="70%"
android:scaleGravity="center"/>
还要设置ScaleDrawable的等级大于0且小于10000:
View testScale = findViewById(R.id.test_scale);
ScaleDrawable testScaleDrawable = testScale.getBackground();
testScaleDrawable.setLevel(1);//没有设置等级这一步,会默认为0不缩放
2.10 ClipDrawable
ClipDrawable可以根据当前的等级(level)来裁剪一个Drawable,裁剪方向通过android:clipOrientation和android:gravity共同控制。
<?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=["left" | "top" | "right" | "bottom" |
"center_vertical" | "center_horizontal" | "fill_vertical" | "fill_horizontal" |
"center" | "fill" | "clip_vertical" | "clip_horizontal"]/>
以上属性说明:
-
top、bottom:将内部的Drawable放在容器的顶部/底部,不改变它的大小。如果为竖直裁剪,那么从底部/顶部开始裁剪。
-
left、right:将内部的Drawable放在容器的左边/右边,不改变它的大小。如果为水平裁剪,那么从右边/左边开始裁剪。默认left。
-
center_vertical/center_horizontal:使内部的Drawable在容器竖直居中/水平居中,不改变它的大小。如果为竖直/水平裁剪,那么从上下同时/左右两边同时裁剪。
-
fill_vertical/fill_horizontal:使内部的Drawable在竖直/水平方向上填充容器。如果为竖直/水平裁剪,那么仅当ClipDrawable的等级为0时,才能有裁剪行为。
-
center:使内部的Drawable在容器中水平和竖直方向都居中,不改变它的大小。如果为竖直裁剪,那么从上下同时开始裁剪;如果为水平裁剪,那么左右同时开始裁剪。
-
fill:使内部的Drawable在水平和竖直方向上同时填充容器。仅当ClipDrawable的等级为0时,才能有裁剪行为。
-
clip_vertical、clip_horizontal:附加选项,表示竖直/水平方向的裁剪,较少使用。
【注:设置等级为0表示完全裁剪,即整个Drawable不可见;10000表示不裁剪】
举例:实现一张图片从上往下裁剪:
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android:
android:clipOrientation="vertical"
android:drawable="@drawable/image1"
android:gravity="bottom"/>
<ImageView
android:id="@+id/test_clip"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/clip_drawable"
android:gravity="center"/>
ImageView testClip = (ImageView) findViewById(R.id.test_clip);
ClipDrawable testClipDrawable = (ClipDrawable) testClip.getBackground();
testClipDrawable/setLevel(5000);
【注:level范围为0-10000,假设设置8000,表示裁剪了20%,根据clipOrientation和gravity裁剪】