Android 的 Drawable ,表示的是一种可以在 Canvas 上进行绘制的抽象的概念。
种类很多,最常见的颜色和图片都可以是一个 Drawable.
1. Drawable 简介
Drawable 有很多种, 它们都表示一种图像的概念,但是它们又不全是图片。
通过颜色也可以构造出各式各样的图像的效果。
开发中,Drawable 常被用来作为 View 的背景使用。
一般通过 XML 文件定义。
在Android的设计中,Drawable是一个抽象类,它是所有Drawable对象的基类,每个具体的Drawable都是它的子类,比如ShapeDrawable、BitmapDrawable等,Drawable的层次关系如图6-1所示。
Drawable的内部宽/高这个参数比较重要,通过getIntrinsicWidth和getIntrinsicHeight这两个方法可以获取到它们。但是并不是所有的Drawable都有内部宽/高,比如一张图片所形成的Drawable,它的内部宽/高就是图片的宽/高,但是一个颜色所形成的Drawable,它就没有内部宽/高的概念。另外需要注意的是,Drawable的内部宽/高不等同于它的大小,一般来说,Drawable是没有大小概念的,当用作View的背景时,Drawable会被拉伸至View的同等大小。
2. Drawable 的分类
Drawable的种类繁多,常见的有BitmapDrawable、ShapeDrawable、LayerDrawable以及StateListDrawable等。
2.1 BitmapDrawable
这几乎是最简单的Drawable了,它表示的就是一张图片。在实际开发中,我们可以直接引用原始的图片即可,但是也可以通过XML的方式来描述它,通过XML来描述的BitmapDrawable可以设置更多的效果.
是否开启图片抗锯齿功能。开启后会让图片变得平滑,同时也会在一定程度上降低图片的清晰度,但是这个降低的幅度较低以至于可以忽略,因此抗锯齿选项应该开启。
2.2 ShapeDrawable
ShapeDrawable是一种很常见的Drawable,可以理解为通过颜色来构造的图形,它既可以是纯色的图形,也可以是具有渐变效果的图形。
2.3 LayerDrawable
LayerDrawable对应的XML标签是,它表示一种层次化的Drawable集合,通过将不同的Drawable放置在不同的层上面从而达到一种叠加后的效果。
一个layer-list中可以包含多个item,每个item表示一个Drawable。Item的结构也比较简单,比较常用的属性有android:top、android:bottom、android:left和android:right,它们分别表示Drawable相对于View的上下左右的偏移量,单位为像素。
另外,我们可以通过android:drawable属性来直接引用一个已有的Drawable资源,也可以在item中自定义Drawable。默认情况下,layer-list中的所有的Drawable都会被缩放至View的大小,对于bitmap来说,需要使用android:gravity属性才能控制图片的显示效果。Layer-list有层次的概念,下面的item会覆盖上面的item,通过合理的分层,可以实现一些特殊的叠加效果。
2.4 StateListDrawable
StateListDrawable对应于标签,它也是表示Drawable集合,每个Drawable都对应着View的一种状态,这样系统就会根据View的状态来选择合适的Drawable。StateListDrawable主要用于设置可单击的View的背景,最常见的是Button
2.5 自定义 Drawable
Drawable 的核心是 draw 方法
系统会调用Drawable的draw方法来绘制View的背景
可以通过重写Drawable的draw方法来自定义Drawable
下面演示一个自定义Drawable的实现过程,我们通过自定义Drawable来绘制一个圆形的Drawable,并且它的半径会随着View的变化而变化,这种Drawable可以作为View的通用背景,代码如下所示
public class CustomDrawable extends Drawable{
private Paint mPaint;
public CustomDrawable(int color){
mPaint = new Paint(Paint.ANTI_ALLAS_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.TRANSLUC
}
}
\