一起来说说那些你不知道的Drawable

Posted Andoter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起来说说那些你不知道的Drawable相关的知识,希望对你有一定的参考价值。

在实际的项目开发中,针对图形资源,我想我们对drawable的使用并不陌生,Drawable很强大,能够帮助我们建立很多多彩的效果,比如我们常见的边框线,就可以通过drawable资源进行构建。

Drawable资源是一个图形的概念,可以被绘制到屏幕上,在开发中,我们通过getDrawable(int resourceId)来生成一个Drawable对象,或者通过android:drawable、android:icon等xml属性来使用Drawable对象。在Android系统中,Drawable资源的分类:

  • BitmapDrawable:代表了图片资源,包括.png、.jpg、.gif图片资源。
  • NinePatchDrawable:代表我们常见的.9.png资源
  • LayerDrawable:代表图层资源,它由一些列的drawable组成,对应的节点layout-list
  • State List:
  • LevelListDrawable
  • TransitionDrawable
  • InsetDrawable
  • ClipDrawable
  • ScaleDrawable
  • ShapeDrawable

一、BitmapDrawable

BitmapDrawable一个由图片生成的Drawable对象。比如我们常用的给控件设置背景图

  • setBackground(Drawable background)
  • setBackgroundDrawable(Drawable background)

这两个方法中,传递的都是Drawable对象,此时就需要我们将图片资源转换为Drawable为对应的BitmapDrawable。在XML文件中,我们通过节点进行配置:

<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@[package:]drawable/drawable_resource"
        android:antialias=["true" | "false"]
        android:dither=["true" | "false"]
        android:filter=["true" | "false"]
        android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                          "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                          "center" | "fill" | "clip_vertical" | "clip_horizontal"]
        android:mipMap=["true" | "false"]
        android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />
  • android:src表示图片源,表示这个bitmap节点应该显示的图片
  • android:antialias是否抗锯齿
  • android:dither如果位图与屏幕的像素配置不同时,是否允许抖动
  • android:filter是否允许对位图进行滤波。对位图进行收缩或者延展使用滤波可以获得平滑的外观效果。
  • android:gravity重力指向参数
  • android:mipMap
  • android:tileMode定义tileMode,当tileMode属性可用时,位图是重复的,并且gravity属性会被忽略。它 有一下几个值:disabled不可用,clamp延伸边缘颜色,repeat:在竖直和水平方向上重复,mirror:以镜像的方式重复

问题:针对ImageView设置backgroud和src属性,对于bitmap的配置属性问题?

我们接下来测试下bitmap属性。首先我们创建一个bitmap_drawable.xml文件,

    <bitmap xmlns:android="http://schemas.android.com/apk/res/android" 
        android:src="@drawable/ic_launcher"
        android:antialias="true"
        android:dither="true"
        />

设置在一个ImageView上进行显示。

        <ImageView
            android:id="@+id/tv_text"
            android:layout_width="150dp"
            android:layout_height="150dp"
            android:layout_centerInParent="true"
            android:background="@drawable/bitmap_drawable"/>

效果是:

                      技术分享

我们设置gravity属性:

    <bitmap xmlns:android="http://schemas.android.com/apk/res/android" 
        android:src="@drawable/ic_launcher"
        android:antialias="true"
        android:dither="true"
        android:gravity="top"
        />

效果图:

                     技术分享

我们分别修改gravity的属性进行测试:

                    技术分享
                    技术分享  
                    技术分享 
                    技术分享

我们接着测试android:tileMode属性,tileMode属性又可以细分为tileModeX和tileModeY两个属性。这两个属性是分别针对X、Y方向上进行变换。

    <bitmap xmlns:android="http://schemas.android.com/apk/res/android" 
        android:src="@drawable/ic_launcher"
        android:antialias="true"
        android:dither="true"
        android:gravity="center_vertical"
        android:tileMode="repeat"
        />

                    技术分享

                     技术分享

其中有个android:tileMode=”clamp”属性,我没有弄出来效果,回头再想想吧!

二、NinePatchDrawable

这个就是我们常见的.9.png图片,这种格式的图片在android 环境下具有自适应调节大小的能力。.9.PNG是安卓开发里面的一种特殊的图片,这种格式的图片通过ADT自带的编辑工具生成,使用九宫格切分的方法,使图片支持在android 环境下的自适应展示。使用配置如下:

    <nine-patch
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:src="@[package:]drawable/drawable_resource"
        android:dither=["true" | "false"] />

三、LayerDrawable

见名思意,这个就是针对图层而来的Drawable对象,它是由很多的drawable对象组成。里面的item根据在list-drawable中的顺序进行绘制。在XML文件中,对应的根节点是layer-list,对应的子节点是item。

    <layer-list
    xmlns:android="http://schemas.android.com/apk/res/android" >
        <item
            android:drawable="@[package:]drawable/drawable_resource"
            android:id="@[+][package:]id/resource_name"
            android:top="dimension"
            android:right="dimension"
            android:bottom="dimension"
            android:left="dimension" />
    </layer-list>

这节点中,layer-list是根节点,它可以包含一个或多个item节点。针对item节点的属性:

  • android:drawable该item对应的drawable属性,可以是drawable资源文件,所以意味着它可以是其它几个drawable对象。
  • android:id该drawable的区别唯一id
  • android:top,right,bottom,left代表该item的内边距大小,即paddingTop,paddingRight,paddingBottom,paddingLeft。

当layer-list中包含多个item时,下面的效果会叠加在上面的效果之上。这点跟PS中的图层叠加的效果是相同的。

我们举个简单的例子:

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
        <item
            android:drawable="@drawable/ic_launcher"
            />
           <item
            android:drawable="@drawable/ic_launcher"
            android:top="20dp"
            android:left="20dp"
            android:bottom="20dp"
            android:right="20dp"
            /> 
    </layer-list>

在这个例子中,我们第一个图层item直接展示了一个drawable/ic_launcher资源,我们设置给一个ImageView它会填充这个背景,在第二个图层中,我们设置了内边距,所以这个item的效果会小于第一个item。二者叠加的效果就如下图:

                    技术分享  
                    

四、StateListDrawable

这个就是我们经常用的状态列drawable,比如我们在实际开发中会有这样一个需求,按下一个按钮,让按钮编程灰色,正常情况下是白色。这样的需求就需要我们根据控件的状态来设置对应的背景色。这里就是使用StateListDrawable对象进行设置。在XML文件中,我们通过标签定义State的集合。每个状态对应一个item。

    <selector xmlns:android="http://schemas.android.com/apk/res/android"
        android:constantSize=["true" | "false"]
        android:dither=["true" | "false"]
        android:variablePadding=["true" | "false"] >
        <item
            android:drawable="@[package:]drawable/drawable_resource"
            android:state_pressed=["true" | "false"]
            android:state_focused=["true" | "false"]
            android:state_hovered=["true" | "false"]
            android:state_selected=["true" | "false"]
            android:state_checkable=["true" | "false"]
            android:state_checked=["true" | "false"]
            android:state_enabled=["true" | "false"]
            android:state_activated=["true" | "false"]
            android:state_window_focused=["true" | "false"] />
    </selector>

注意:在一个selector中可以包含多个item节点,android系统查找的顺序是从上往下查找状态,查找到满足条件的即停止向下查找对应的drawable。所以这就需要我们在放置item的位置时,进行考虑,防止item的覆盖,出现效果错乱。

    <selector xmlns:android="http://schemas.android.com/apk/res/android" >
        <item android:state_pressed="true" android:drawable="@drawable/btn_press"/>
        <item android:state_pressed="false" android:drawable="@drawable/btn_unpress"/>
        <item android:drawable="@drawable/btn_normal"/>
    </selector>

在上面的selector中,我们指定了按下的、非按钮、正常情况下的drawable效果,这里,我们就不能把后两个写反。我们先来看看这个的效果:

                技术分享

如果我们把item的顺序改变。

    <selector xmlns:android="http://schemas.android.com/apk/res/android" >
        <item android:state_pressed="true" android:drawable="@drawable/btn_press"/>
        <item android:drawable="@drawable/btn_normal"/>
        <item android:state_pressed="false" android:drawable="@drawable/btn_unpress"/>
    </selector>

此时系统会给我们一个警告:This item is unreachable because a previous item (item #2) is a more general match than this one,意思就是说第三个item到达不了,上一个item比这个item优先匹配到。对应的效果图:

                  技术分享

效果就是这样,所以在我们使用时,一定要注意放置的item顺序。

五、LevelListDrawable

等级列表Drawable,就是根据我们设置的等级展现对应的drawable对象。我们通过Drawable的.setLevel()方法设置等级。

<level-list
    xmlns:android="http://schemas.android.com/apk/res/android" >
        <item
            android:drawable="@drawable/drawable_resource"
            android:maxLevel="integer"
            android:minLevel="integer" />
    </level-list>
  • android:maxLevel:最大等级
  • android:minLevel:最小等级

案例:

    <level-list xmlns:android="http://schemas.android.com/apk/res/android" >
        <item
            android:drawable="@drawable/btn_press"
            android:maxLevel="0" />
        <item
            android:drawable="@drawable/btn_normal"
            android:maxLevel="1" />
    </level-list>

我们利用按钮点击改变:

    btn_btn .setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if(index % 2 ==0){  
                    btn_btn.setText("等级为0");
                    btn_btn.getBackground().setLevel(0);
                }else{
                    btn_btn.setText("等级为1");
                    btn_btn.getBackground().setLevel(1);
                }
                index++;
            }
        });

效果图:

                  技术分享

注意:在level-list中,同样是从上到下根据level处在的范围进行获取drawable。比如,我们对一个item设置的level在0——5之间,我们设置level=2,则处在该范围,所以取该drawable。

六、TransitionDrawable

android中的过渡动画。

    <transition
    xmlns:android="http://schemas.android.com/apk/res/android" >
        <item
            android:drawable="@[package:]drawable/drawable_resource"
            android:id="@[+][package:]id/resource_name"
            android:top="dimension"
            android:right="dimension"
            android:bottom="dimension"
            android:left="dimension" />
    </transition>

使用方法:

    ImageButton button = (ImageButton) findViewById(R.id.button);
    TransitionDrawable drawable = (TransitionDrawable) button.getDrawable();
    drawable.startTransition(500);

七、InsetDrawable

用于通过指定的间距把图片插入到XML中,它在View需要比自身小的背景时常用。有些像padding的作用。

    <inset
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/drawable_resource"
        android:insetTop="dimension"
        android:insetRight="dimension"
        android:insetBottom="dimension"
        android:insetLeft="dimension" />

例如:

    <inset xmlns:android="http://schemas.android.com/apk/res/android" 
        android:drawable="@drawable/ic_launcher"
        android:insetLeft="20dp"
        android:insetRight="20dp"
        android:insetTop="20dp"
        android:insetBottom="20dp"
        >
    </inset>

效果图:
                     技术分享

八、ClipDrawable

可以剪载图片显示,根据当前drawable的level属性曲去裁剪drawable,通过gravity属性设置获取的位置。例如,可以通过它来做进度度。你可以选择是从水平或垂直方向剪载。其中的gravity设置从整个部件的哪里开始。

    <clip
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:clipOrientation=["horizontal" | "vertical"]
    android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                     "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                     "center" | "fill" | "clip_vertical" | "clip_horizontal"] />

例如:

    <clip xmlns:android="http://schemas.android.com/apk/res/android" 
        android:clipOrientation="horizontal"
        android:gravity="left"
        android:drawable="@drawable/btn_press"
        >
    </clip>

我们的使用:

    btn_btn .setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                ClipDrawable drawable = (ClipDrawable) btn_btn.getBackground();
                drawable.setLevel(drawable.getLevel() + 1000);
            }
    });

我们看看效果图:

                     技术分享

是不是有一种进度条的效果。哈哈

九、ScaleDrawable

以drawable的level值为基础,进行大小的改变。

    <scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                          "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                          "center" | "fill" | "clip_vertical" | "clip_horizontal"]
    android:scaleHeight="percentage"
    android:scaleWidth="percentage" />
  • android:scaleHeight:缩放高度,缩放的百分比,比如10%,则最终的高度为原图的90%;
  • android:scaleWidth:缩放宽度

使用如下:

    ScaleDrawable drawable = (ScaleDrawable) btn_btn.getBackground();
    drawable.setLevel(3);

十、Shape Drawable

这个是我们实际开发中使用最多的一个drawable,我们设置边框线,阴影。都是要使用这个进行设置。

<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape=["rectangle" | "oval" | "line" | "ring"] >
        <corners
            android:radius="integer"
            android:topLeftRadius="integer"
            android:topRightRadius="integer"
            android:bottomLeftRadius="integer"
            android:bottomRightRadius="integer" />
        <gradient
            android:angle="integer"
            android:centerX="integer"
            android:centerY="integer"
            android:centerColor="integer"
            android:endColor="color"
            android:gradientRadius="integer"
            android:startColor="color"
            android:type=["linear" | "radial" | "sweep"]
            android:useLevel=["true" | "false"] />
        <padding
            android:left="integer"
            android:top="integer"
            android:right="integer"
            android:bottom="integer" />
        <size
            android:width="integer"
            android:height="integer" />
        <solid
            android:color="color" />
        <stroke
            android:width="integer"
            android:color="color"
            android:dashWidth="integer"
            android:dashGap="integer" />
    </shape>

我们针对各个节点的属性进行说明:
corners圆角属性

  • android:radius四个角的圆角大小
  • android:topLeftRadius左上角的圆角大小
  • android:topRightRadius右上角的圆角大小
  • android:bottomLeftRadius左下角圆角的大小
  • android:bottomRightRadius右下角圆角的大小

gradient渐变属性

  • android:angle渐变起始角
  • android:centerX中间点的X坐标
  • android:centerY中间点的Y坐标
  • android:startColor起始颜色
  • android:centerColor中间控制颜色
  • android:endColor中止颜色值
  • android:gradientRadius渐变的圆角
  • android:type渐变的类型,有线性、圆形、扇形
  • android:useLevel是否使用level

padding内边距属性

  • android:left左内边距
  • android:top上内边距

Size大小

  • android:width宽度
  • android:height高度

solid绘制

  • android:color绘制的颜色

stroke描边

  • android:width描边的宽度
  • android:color描边的颜色
  • android:dashWidth间隔线宽度
  • android:dashGap间隔线的距离

补充,当我们设置android:shape=”ring”时,有以下几个属性需要注意:

  • android:innerRadius
  • android:innerRadiusRatio
  • android:thickness
  • android:thicknessRatio
  • android:useLevel

接着来演示一个demo

    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
        <gradient
            android:startColor="#FFFF0000"
            android:endColor="#80FF00FF"
            android:angle="45"/>
        <padding android:left="7dp"
            android:top="7dp"
            android:right="7dp"
            android:bottom="7dp" />
        <corners android:radius="8dp" />
    </shape>

                   技术分享 
                  技术分享

至此,针对各个大类的Drawable的基本属性已经介绍完毕,下篇我们就练习下几个实际案例。








以上是关于一起来说说那些你不知道的Drawable的主要内容,如果未能解决你的问题,请参考以下文章

蓝牙耳机知识科普——那些你不知道的解码方式

提效小技巧——记录那些不常用的代码片段

那些你不知道的HTML知识,快来学习一下吧

那些你不知道的炫酷导航交互效果

Android drawable微技巧,你所不知道的drawable的那些细节

有关Color和Drawable你所不知道的那些内容