Android 中的 Drawable

6.1 Drawable 简介


Android 中的 Drawable 表示一种可以在 Canvas 上进行绘制的抽象的概念,比如颜色和图片都可以是一个 Drawable。

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 :四周的像素扩散到周围
tileMode 平铺效果

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(扫描线渐变)

从左到右依次是: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>
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);
TransitionDrawable 效果图

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>
image.png

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);
image.png

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);
竖直裁剪 20 %

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);
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 优点:使用简单,比自定义View的成本低;非图片类型的Drawable占用空间较小,这对减小apk的大小也有很大的...
    小柏不是大白阅读 2,284评论 0 1
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • Android中Drawable是一种可以在Canvas上进行绘制抽象的概念,种类很多,常见的颜色和图片都可以是一...
    斜杠时光阅读 1,228评论 0 7
  • 前言 本文是本人阅读《Android开发艺术探索》的第6章《Android的Drawable》后的总结笔记。包含了...
    daking阅读 5,295评论 2 29
  • 01 沉睡了一夜后,打破村庄寂静的总是那一声声如约而来的响亮而持久的鸡鸣声。一声鸡鸣声就可以响彻整个村庄,它就如同...
    杨喜爱阅读 1,415评论 11 158