6.1 Drawable 简介
Android 中的 Drawable 表示一种可以在 Canvas 上进行绘制的抽象的概念,比如颜色和图片都可以是一个 Drawable。
6.2 Drawable 的分类
6.2.1 BitmapDrawable
BitmapDrawable 表示一张图片,可以用原始图片显示,也可以用 XML 的方式。
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/image1" //图片资源 id
android:antialias="true" //抗锯齿
android:dither="true" //抖动
android:filter="true"
android:gravity="center"
android:mipMap="false"
android:tileMode="disabled">
</bitmap>
-
android:src
图片资源 id -
android:antialias
抗锯齿,开启后让图片变得平滑。 -
android:dither
抖动效果,开启后图像在不同屏幕上的显示效果越逼真。 -
android:filter
过滤效果,当图片尺寸被拉伸,开启过滤效果可以保持较好的显示效果。 -
android:gravity
对图片在容器中定位。 -
android:mipMap
这一种图像相关的处理技术,也叫纹理映射,比较抽象,默认 false,不用深究。 - android:tileMode
- disabled :禁用
- repeat :水平和竖直方向上的平铺效果
- mirror :水平和竖直方向上的镜面投影效果
- clamp :四周的像素扩散到周围
6.2 ShapeDrawable
ShapeDrawable 可以理解为通过颜色来构造的图形,可以是纯色或者具有渐变的图形。需要注意的是<shape>标签创建的 Drawable 其实体类是 GradientDrawable。
-
android:shape
表示图形的形状,有四个选项: - rectangle(矩形):默认选择
- oval(椭圆)
- line(横线):必须通过<stroke>标签来指定线的宽度和颜色等信息
- ring(圆环):必须通过<stroke>标签来指定线的宽度和颜色等信息
value | Desciption |
---|---|
android:innerRadius | 圆环的内半径,和 android:innerRadiusRatio 同时存在时,以android:innerRadius为准 |
android:thickness | 圆环的厚度,即半径减去内半径的大小 |
android:innerRadiusRatio | 内半径占整个 Drawable 宽度的比例,默认值为 9。如果为 n,那么内半径 = 宽度 / n |
android:thicknessRatio | 厚度占整个 Drawable 宽度的比例,默认值为 3,,如果为 n,那么厚度 = 宽度 / n |
android:useLevel | 一般都应该使用 false |
<corners>
表示 shape 四个角的角度,只适用于矩形 shape,用 px 来表示:android:radius —— 为四个角同时设定相同的角度;
android:topRightRadius —— 设定右上角的角度;
android:bottomLeftRadius —— 设定左下角的角度;
android:bottomRightRadius —— 设定右下角的角度;
<gradient>
它与<soild>标签是互相排斥的,soild 表示纯色填充,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 使用时为 true;
android:type —— 渐变的类别,linear(线性渐变)、radial(径向渐变)、sweep(扫描线渐变)
<soild>
纯色填充<stroke>
Shape 的描边android:width —— 描边的宽度;
android:color —— 描边的颜色;
android: dashWidth —— 组成虚线的线段的宽度;
android:dashGap —— 组成虚线的线段之间的间隔;
<padding>
四个属性:android:left、top、right、bottom<size>
shape 的大小,有两个属性:android:width、height,表示 shape 的固有大小,但作为 View 的背景时,还是会被显示为 View 的大小。
6.2.3 LayerDrawable
LayerDrawable 对应的 XML 标签是<layer-list> ,通过不同的 Drawable 放置不再通的层上面从而达到一种叠加后的效果。
<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>
6.2.4 StateListDrawable
StateListDrawable 对应<selector> 标签,表示 Drawable 的集合。
android:constantSize
StateListDrawable 的固有大小是否随着其状态的改变而改变,因为状态的改变而切换到具体的 Drawable,为 true 则表示 StateListDrawable 的固有大小是所有 Drawable 最大值并且保持不变,默认为 false,会改变。android:dither
开启抖动效果,默认为 true,开启后在低质量的屏幕上仍有较好的显示效果。android:variablePadding
StateListDrawable 的 padding 是否随其状态的改变而改变,true 是改变,默认为 false(推荐)。<item>
表示一个具体的 Drawable。
状态 | 含义 |
---|---|
android:state_proessed | 表示按下状态 |
android:state_focused | 表示 View 已经获取了焦点 |
android:state_selected | 表示用户选择了焦点 |
android:state_checked | 表示用户选中了 View,一般适用于 CheckBox 这类。 |
android:state_enabled | 表示 View 当前处于可用状态 |
6.2.5 LeveListDrawable
LeveListDrawable 对应于 <level-list> 标签,表示一个 Drawable 集合,根据其中的 level 来切换对应的 Drawable。
- 作为 View 的背景:通过 setLevel 来切换
- 作为 ImageView 的前景 Drawable:通过 ImageView.setImageLevel 来切换。
6.2.6 TransitionDrawable
TransitionDrawable 对应于<transiton>标签,用于实现两个 Drawable 之间的淡入淡出效果。
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/bitmap_drawable_clamp"/>
<item android:drawable="@drawable/bitmap_drawable_mirror"/>
</transition>
TransitionDrawable drawable = (TransitionDrawable) button.getBackground();
drawable.startTransition(3000);
6.2.7 InsetDrawable
InsetDrawable 对应于<inset>标签,它可用将其他 Drawable 内嵌到自己当中,并可用在四周流出一定的间距。
<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>
6.2.8 ScaleDrawable
ScaleDrawable 对应于<scale>标签,下面案例:显示 30% 的大小
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/image1"
android:scaleHeight="70%"
android:scaleWidth="70%"
android:scaleGravity="center" />
必须设置一个比 大于 0 小于 10000 的数字,否则无效
ScaleDrawable drawable = (ScaleDrawable) button.getBackground();
drawable.setLevel(1);
6.2.9 ClipDrawable
ClipDrawable 对应于<clip>标签,它可以根据自己当前的等级(level)来裁剪另一个 Drawable。
android:clipOrientation
horizontal:横向
vertical:竖向
android:gravity
选项 | 含义 |
---|---|
top | 将内部的 Drawable 放在容器的顶部,不改变它的大小。如果为竖直裁剪,那么从底部开始裁剪。 |
bottom | 将内部的 Drawable 放在容器的底部,不改变它的大小。如果为竖直裁剪,那么从顶部开始裁剪 |
left | 将内部的 Drawable 放在容器的左边,不改变它的大小。如果为水平裁剪,那么从右边开始裁剪(默认) |
right | 将内部的 Drawable 放在容器的右,不改变它的大小。如果为水平裁剪,那么从左边开始裁剪 |
center_vertical | 将内部的 Drawable 在容器中竖直居中,不改变它的大小。如果为竖直裁剪,那么从上下同时开始裁剪 |
fill_vertical | 使内部的 Drawable 在竖直方向上填充容器,如果为竖直裁剪。那么仅当 ClipDrawable 的等级为 0(0 表示 ClipDrawable 被完全裁剪,既不可见)时,才能有裁剪行为 |
fill_horizontal | 使内部的 Drawable 在水平方向上填充容器,如果为水平裁剪。那么仅当 ClipDrawable 的等级为 0时,才能有裁剪行为 |
center | 使内部的 Drawable 在水平和竖直方向上都居中,不改变它的大小。如果为竖直裁剪,那么从上下同时开始裁剪,如果为水平裁剪,那么从左右同时开始裁剪 |
fill | 使内部的 Drawable 在水平和竖直方向上同时填充容器,仅当 ClipDrawable 的等级为 0时,才能有裁剪行为 |
clip_vertical | 附加选项,表示竖直方向裁剪,较少使用 |
clip_horizontal | 附加选项,表示水平方向裁剪,较少使用 |
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="vertical"
android:drawable="@drawable/image1"
android:gravity="bottom" />
0-10000区间
ClipDrawable drawable = (ClipDrawable) button.getBackground();
drawable.setLevel(8000);
6.3 自定义 Drawable
很简单,继承 Drawable 实现里面的四个方法。
public class CustomDrawable extends Drawable {
private Paint mPaint;
public CustomDrawable(int color) {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(color);
}
@Override
public void draw(Canvas canvas) {
final Rect r = getBounds();
float cx = r.exactCenterX();
float cy = r.exactCenterY();
canvas.drawCircle(cx, cy, Math.min(cx, cy), mPaint);
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
invalidateSelf();
}
@Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
invalidateSelf();
}
@Override
public int getOpacity() {
// not sure, so be safe
return PixelFormat.TRANSLUCENT;
}
View testCustomDrawable = findViewById(R.id.test_custom_drawable);
CustomDrawable customDrawable = new CustomDrawable(Color.parseColor("#0ac39e"));
testCustomDrawable.setBackgroundDrawable(customDrawable);