Android 的 Drawable

253 阅读3分钟

Android 的 Drawable ,表示的是一种可以在 Canvas 上进行绘制的抽象的概念。

种类很多,最常见的颜色和图片都可以是一个 Drawable.

1. Drawable 简介

Drawable 有很多种, 它们都表示一种图像的概念,但是它们又不全是图片。

通过颜色也可以构造出各式各样的图像的效果。

开发中,Drawable 常被用来作为 View 的背景使用。

一般通过 XML 文件定义。

在Android的设计中,Drawable是一个抽象类,它是所有Drawable对象的基类,每个具体的Drawable都是它的子类,比如ShapeDrawable、BitmapDrawable等,Drawable的层次关系如图6-1所示。

image-20211015161013516

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

\