Drawable及其子类

在Android系统中,Drawable是一个抽象类,它是所有Drawable对象的基类,它有很多子类,比较常见的有ShapeDrawable、BitmapDrawable、ColorDrawable等。

Drawable的内部宽高尺寸是通过getIntrinsicWidth和getIntrinsicHeight方法来获取的,但并不是所有Drawable都有内部宽高尺寸这个参数的,比如ColorDrawable和ShapeDrawable就没有,而图片形成的Drawable就有,它的内部宽高就是图片的宽高。

  • BitmapDrawable表示的就是一张图片,使用时我们除了可以直接引用原始的图片,还可以通过xml描述BitmapDrawable,比如:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:antialias="true"
    android:dither="true"
    android:filter="true"
    android:gravity="center"
    android:mipMap="false"
    android:src="@drawable/rn_finish"
    android:tileMode="clamp" />

其中的属性是不是好像在哪见过?没错,在自定义View时,我们会使用Paint,Paint就可以设置这些属性,基本上这些属性的含义都是一样的。antialias表示是否抗锯齿,抗锯齿的效果是在图片边缘会表现的更圆润,而实际上加了抗锯齿效果边缘会变的模糊,所以看起来会圆滑。dither表示是否开启抖动效果,当图片的像素配置和手机屏幕的像素配置不一致时,开启抖动效果可以让高质量的图片在低质量的屏幕上还能保持较好的显示效果,比如图片的色彩模式为ARGB8888,但手机屏幕支持的色彩模式为RGB555,如果开启抖动效果就可以让图片显示不会过于失真。filter表示是否开启过滤效果,当图片尺寸被拉伸或者压缩时,开启过滤效果可以保持较好的显示效果。src表示图片的资源id。gravity表示图片在容器中的位置。tileMode表示图片的平铺模式,默认是disbaled,另外还有三个选项mirror、repeat、clamp,repeat是重复,mirror是对称翻转,clamp是延伸。

另外NinePatchDrawable表示的是一张.9格式的图片,.9图片可以自动根据所需的宽高进行相应的缩放来保证不失真。同样它也可以使用xml来描述,在xml中的节点名是nine-patch,其他属性和bitmap是一样的,而且在bitmap标签中也可以使用.9图片,所以BitampDrawable也可以表示一个.9格式的图片。

  • ShapeDrawable可以通过颜色来构造图形,比如当我们要为一个按钮加上一个圆角的纯色背景时,找UI切图太麻烦了,我们完全可以使用ShapeDrawable来实现。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners
        android:bottomLeftRadius="5dp"
        android:bottomRightRadius="5dp"
        android:radius="20dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />

    <gradient
        android:angle="90"
        android:centerColor="@color/colorPrimaryDark"
        android:centerX="100dp"
        android:centerY="100dp"
        android:endColor="@color/colorAccent"
        android:gradientRadius="10dp"
        android:startColor="@color/colorPrimary"
        android:type="radial"
        android:useLevel="false" />

    <padding
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp" />


    <size
        android:width="200dp"
        android:height="200dp" />


    <solid android:color="@color/colorPrimary" />


    <stroke
        android:width="10dp"
        android:color="@color/colorAccent"
        android:dashGap="1dp"
        android:dashWidth="2dp" />

</shape>

以上是shape标签下所有的属性和子标签了,分别解释下其意思。

  • 属性shape表示图形的形状,共有四个可选值,line是直线,rectangle是矩形,oval是椭圆形,ring是圆环,默认值是矩形,其中line和ring这两个选项必须通过stroke标签来确定形状的宽度和颜色等信息,否则可能会无法显示正常。(而且ring这个形状还有5个额外的属性,innerRaius表示圆环的内半径,thickness表示圆环的厚度,innerRadiusRatio表示内半径占整个Drawable宽度的比例,默认是9,thicknessRatio表示厚度占整个Drawable宽度的比例,默认是3,useLevel表示是否使用等级,一般都是false。)

  • corners表示圆角半径,这个标签只适合rectangle形状,radius表示四个角设置为相同的圆角半径,还有四个分别表示四个角的圆角半径的属性topLeftRaduis、topRightRadius、bottomLeftRadius、bottomRightRadius,如果设置了这四个中的某一个,那么它会覆盖前面的radius属性所设置的值。

  • solid是使用纯色填充图形,只有一个属性color,表示要填充图形的颜色。

  • gradient表示图形的渐变效果,它与solid标签是不能同时使用的,solid是使用纯色填充图形,gradient则是渐变,它几个属性的含义如angle表示渐变的角度,默认是0,其值必须是45的倍数,0表示从左到右,90表示从下到上。centerX表示渐变中心点的横坐标,centerY表示渐变中心点的纵坐标,startColor表示渐变的起始色,endColor表示渐变的结束色,centerColor表示渐变的中间色,gradientRadius表示渐变半径,这个属性只有当type属性值为radial时才有效,type有三个选项,linear表示线性渐变,radial表示辐射渐变,也就是以圆环的形状渐变,sweep表示扫描渐变。

  • stroke表示图形的描边,width表示描边的宽度,color表示描边的颜色,这俩属性可以决定我们背景shape的边框颜色和边框粗细,dashWidth表示组成虚线的线段的宽度,dashGap表示虚线线段之间的间隔,

  • size表示shape的大小,其实就是给shape设置固有的宽高,我们知道ShapeDrawable本身是没有固有宽高的,但是如果设置了size,那么它就有了,不过当把它设置给View的背景时,还是会被拉伸或缩小来适应View的宽高的。

LayerDrawable对应的xml标签是<layer-list>,看字面意思我们就知道它是一种层次化的Drawable集合,通过将不同的Drawable放在不同的层上来达到一种叠加效果。

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

其中item的left、right、top和bottom属性表示相对于View的上下左右的偏移量,item也可以直接使用drawable属性来引用一个已有的Drawable资源。另外下面的item会覆盖上面的item,达到叠加效果。

StateListDrawable对应于<selector>标签,它和LayerDrawable一样也是表示Drawable的集合,它每个Drawable都对应着一种状态,系统会根据View不同的状态来选择合适的Drawable。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@color/colorAccent" android:state_checked="true" />
    <item android:drawable="@color/colorAccent" android:state_focused="true" />
    <item android:drawable="@color/colorAccent" android:state_enabled="true" />
    <item android:drawable="@color/colorAccent" android:state_hovered="true" />
    <item android:drawable="@color/colorAccent" android:state_window_focused="true" />
    <item android:drawable="@color/colorPrimary" />

</selector>

selector标签本身几个属性的含义:

  • constantSize表示StateListDrawable的固有大小是否随着状态的改变而改变,true表示不改变,默认为false。
  • dither表示是否开启抖动效果,这个和BitmapDrawable中的一样,默认是true。
  • variablePadding表示StateListDrawable的padding是否随着状态的改变而改变,true表示随着状态的改变而改变,false表示StateListDrawable的padding是内部所有Drawable的padding的最大值,默认为false。

对于常使用的几种状态,state_pressed表示按压,state_enabled表示当前可用,state_checked表示选中,state_focused表示获取到焦点,state_selected表示已选择。其他几个基本不会使用到。

LevelListDrawable对应于<level-list>标签,它也表示一个Drawable集合,集合中的Drawable都有一个level,根据不同的level,LevelListDrawable会切换到对应的Drawable。

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:drawable="@color/colorAccent"
        android:maxLevel="10"
        android:minLevel="1" />

    <item
        android:drawable="@color/colorPrimary"
        android:maxLevel="100"
        android:minLevel="11" />

    <item
        android:drawable="@color/colorPrimaryDark"
        android:maxLevel="1000"
        android:minLevel="101" />

</level-list>

它的每个item都表示一个Drawable,通过maxLevel和minLevel来控制level,level数值在0~10000之间,最小是0,最大10000,默认是0。

TransitionDrawable对应xml中的<transition>标签,它用于两个Drawable之间实现淡入淡出的效果。

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@color/colorAccent" />
    <item android:drawable="@color/colorPrimaryDark" />

</transition>

实际使用中是将上面的TransitionDrawable设置为View的背景,然后在代码中通过View获取其background,强转成TransitionDrawable,然后调用其startTransition(int duration)方法来实现Drawable切换的效果,duration是完成切换的时间。也可以通过startTransition结合reverseTransition来实现其反向切换过程。

InsetDrawable对应xml中的<inset>标签,它可以将其他Drawable内嵌到自己中,并可以在周围留出一定的间距。当一个View需要自己的背景比自己的实际区域小时就可以采用InsetDrawable来实现。

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetBottom="10dp"
    android:insetLeft="10dp"
    android:insetRight="10dp"
    android:insetTop="10dp">

    <shape android:shape="rectangle">
        <solid android:color="@color/colorAccent" />
    </shape>

</inset>

ScaleDrawable对应xml中的<scale>标签,它可以根据自己的level将指定的Drawable缩放到一定比例。

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/rn_finish"
    android:scaleGravity="center"
    android:scaleHeight="25%"
    android:scaleWidth="30%">

</scale>

其中android:scaleHeight和android:scaleWidth分别表示对指定Drawable宽高的缩放比例,以百分比的形式表示。ScaleDrawable的level为0时不可见,0也是默认值,只有当等级不等于0时ScaleDrawable才会可见。

另外ScaleDrawable的level最大值为10000,最大时就没有缩放的效果,level越大,内部的Drawable看起来就越大,如果ScaleDrawable的xml中所定义的缩放比越大,那么内部的Drawable看起来就越小。

TextView view = (TextView) findViewById(R.id.view);
ScaleDrawable scaleDrawable = (ScaleDrawable) view.getBackground();
scaleDrawable.setLevel(9999);

这里要注意的是必须将level设置为大于0,少了这一步,ScaleDrawable将无法显示。

ClipDrawable对应xml中的<clip>标签,它根据自己当前的level来裁剪另一个Drawable,裁剪方向可以通过clipOrientation和gravity共同控制,clipOrientation是裁剪方向,gravity表示Drawable在容器内的位置以及影响开始裁剪的位置。

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:drawable="@drawable/rn_finish"
    android:gravity="top">

</clip>
<ImageView
    android:id="@+id/imageview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:src="@drawable/clip" />

clipOrientation="vertical"表示竖直方向裁剪,gravity=“top”表示从底部开始裁剪,接着在代码中设置ClipDrawable的level:

ImageView imageView = (ImageView) findViewById(R.id.imageview);
ClipDrawable clipDrawable = (ClipDrawable) imageView.getDrawable();
clipDrawable.setLevel(10000);

ClipDrawable的level为0时表示完全裁剪,为10000时表示不裁剪,范围也是0~10000,设置8000表示裁剪了20%,设置3000表示裁剪了70%。等级越大裁剪的区域越小。

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

推荐阅读更多精彩内容

  • 概述 今天我们来探究一下android的样式。其实,几乎所有的控件都可以使用 background属性去引用自定义...
    CokeNello阅读 4,794评论 1 19
  • 转载自Keegan小钢并标明原文链接:http://keeganlee.me/post/android/20150...
    坚持编程_lyz阅读 1,099评论 0 1
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,042评论 25 707
  • 突然脑袋很沉,,,,只想回到寝室睡觉,没有其他想法,,,,hhhhhh,最近兴奋的不正常,12点半睡,6点起。
    瓜宁阅读 87评论 0 0
  • 盟盟宝贝: 在你咿咿呀呀吵闹哭泣的日子里,时间总是过得飞快,转眼你就满月了。 你那瘦弱的小身体变得肉呼呼圆嘟嘟,双...
    kakawys阅读 729评论 0 0