Android各种Drawable基础讲解以及使用实例

转载自  :

https://blog.csdn.net/linghu_java/article/details/42119969

       Android把可绘制的对象抽象为Drawable,不同的图形图像资源就代表着不同的drawable类型。Android FrameWork提供了一些具体的Drawable实现,通常在代码中都不会直接接触Drawable的实现类。

        在实际的开发过程中,会把使用到的资源都放置在res/drawable目录,剩下的工作交给Android SDK 就行了,当需要使用图片资源的时候,可以使用@drawable标志在xml中引用drawable资源就行,也可以在代码中使用id引用这些drawable资源.

        在使用drawable资源的时,有一点需要注意,drawable默认是内存共享的,也就说在不同的地方使用了同一个drawable,它们都指向相同的资源,而且具有相同的状态,如果在一个地方修改了这个drawable,所有使用它的地方都会改变。

        Android内置了如下几种Drawable类型:ColorDrawable、GradientDrawable、BitmapDrawable、 NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、RotateDrawable、AnimationDrawable、LayerDrawable、LevelListDrawable、StateListDrawable、TransitionDrawable.

       除了这些预置的drawable实现类以外,也可以自定义drawable的实现类型,大部分情况都不需要自定义drawable类型,使用系统提供的这些drawable实现类型已经覆盖了很多情况。在实际的编程过程中也很少会接触这些具体drawable实现类型,因为编写android应用程序使用xml可以很容易的创建drawable,只有在程序中需要修改drawable的属性时,才需要使用具体的drawable类型提供的方法来处理。下面就来逐个认识这些Drawable类型。

一、ColorDrawable

        ColorDrawable 是最简单的Drawable,它实际上是代表了单色可绘制区域,它包装了一种固定的颜色,当ColorDrawable被绘制到画布的时候会使用颜色填充Paint,在画布上绘制一块单色的区域。

        在xml文件中使用color作为根节点来创建ColorDrawable,它只有一个android:color属性,通过它来决定ColorDrawable的颜色,Android并没有提供修改这个颜色值的Api,所以这个颜色一旦设置之后,就不能直接修改了。

 下面的xml文件定义了一个颜色为红色的ColorDrawable:

[代码]xml代码:

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

        当然也可以使用Java代码创建ColorDrawable,需要注意的是Android中使用一个int类型的数据表示颜色值,通常习惯使用十六进制格式的数据表示颜色值。一个int类型包含四个字节,分别代表颜色的4个组成部分:透明度(Alpha)、红(RED)、绿(GREEN)、蓝(BLUE),每个部分由一个字节(8个bit)表示,取值范围为0~255。在xml中使用颜色时可以省略透明度(Alpha)部分,如#ff0000表示红色。但是在代码中必须要明确指出透明度(Alpha)代表的数据,如果省略了就表示完全透明的颜色,例如0xFFFF0000表示红色,而0xFF0000虽然也表示红色,但它却是完全透明的,也就是说当绘制到画布上时,看不出有任何效果.

        使用Java代码也可以创建ColorDrawable,代码如下:

[代码]java代码:

ColorDrawable drawable = new ColorDrawable(0xffff0000);

二、GradientDrawable

GradientDrawable 表示一个渐变区域,可以实现线性渐变、发散渐变和平铺渐变效果,在Android中可以使用GradientDrawable表示很多复杂而又绚丽的界面效果。

    可以使用xml定义GradientDrawable,相对于ColorDrawable类型,GradientDrawable要复杂很多,它有很多的元素组成。在xml文件中使用shape作为根节点来创建GradientDrawable,它包含很多属性和子节点,下面是GradientDrawable的xml文档节点结构。

[代码]xml代码:

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

    <size/>// 定义区域的大小
    
    <gradient/>//设置区域背景的渐变效果

    <solid/> //设置区域的背景颜色,如果设置了solid会覆盖gradient的效果

    <stroke/> //设置区域的边框效果

    <padding/> //设置区域的内边距

</shape>

在我们实际操作shape的时候我们需要先了解shape的各种属性的作用:

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape=["rectangle" | "oval" | "line" | "ring"]      //共有4种类型,矩形(默认)/椭圆形/直线形/环形
    // 以下4个属性只有当类型为环形时才有效
    android:innerRadius="dimension"     //内环半径
    android:innerRadiusRatio="float"    //内环半径相对于环的宽度的比例,比如环的宽度为50,比例为2.5,那么内环半径为20
    android:thickness="dimension"   //环的厚度
    android:thicknessRatio="float"     //环的厚度相对于环的宽度的比例
    android:useLevel="boolean">    //如果当做是LevelListDrawable使用时值为true,否则为false.
 
    <corners    //定义圆角
        android:radius="dimension"      //全部的圆角半径
        android:topLeftRadius="dimension"   //左上角的圆角半径
        android:topRightRadius="dimension"  //右上角的圆角半径
        android:bottomLeftRadius="dimension"    //左下角的圆角半径
        android:bottomRightRadius="dimension" />    //右下角的圆角半径
 
    <gradient   //定义渐变效果
        android:type=["linear" | "radial" | "sweep"]    //共有3中渐变类型,线性渐变(默认)/放射渐变/扫描式渐变
        android:angle="integer"     //渐变角度,必须为45的倍数,0为从左到右,90为从上到下
        android:centerX="float"     //渐变中心X的相当位置,范围为0~1
        android:centerY="float"     //渐变中心Y的相当位置,范围为0~1
        android:startColor="color"      //渐变开始点的颜色
        android:centerColor="color"     //渐变中间点的颜色,在开始与结束点之间
        android:endColor="color"    //渐变结束点的颜色
        android:gradientRadius="float"  //渐变的半径,只有当渐变类型为radial时才能使用
        android:useLevel=["true" | "false"] />  //使用LevelListDrawable时就要设置为true。设为false时才有渐变效果
 
    <padding    //内部边距
        android:left="dimension"
        android:top="dimension"
        android:right="dimension"
        android:bottom="dimension" />
 
    <size   //自定义的图形大小
        android:width="dimension"
        android:height="dimension" />
 
    <solid  //内部填充颜色
        android:color="color" />
 
    <stroke     //描边
        android:width="dimension"   //描边的宽度
        android:color="color"   //描边的颜色
        // 以下两个属性设置虚线
        android:dashWidth="dimension"   //虚线的宽度,值为0时是实线
        android:dashGap="dimension" />      //虚线的间隔
</shape>

以下是几种不同渐变效果实现的xml文件代码:

<?xml version="1.0" encoding="utf-8"?>
<!--线性渐变的椭圆-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <gradient
        android:type="linear"
        android:angle="90"
        android:gradientRadius="200dp"
        android:startColor="#e61010"
        android:centerColor="#38df0e"
        android:endColor="#d7da08"/>
    <stroke
        android:color="#ffffff"
        android:width="3dp"
        android:dashGap="5dp"
        android:dashWidth="5dp"/>
</shape>

<?xml version="1.0" encoding="utf-8"?>
<!--平铺渐变的圆环-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="ring"
    android:innerRadiusRatio="8"
    android:thicknessRatio="3"
    android:useLevel="false"
    >
    <gradient
        android:type="sweep"
        android:useLevel="false"
        android:gradientRadius="200dp"
        android:startColor="#e61010"
        android:centerColor="#38df0e"
        android:endColor="#d7da08"/>
</shape>

<?xml version="1.0" encoding="utf-8"?>
<!--发散渐变效果的圆-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="ring"
    android:innerRadius="0dp"
    android:thickness="70dp"
    android:useLevel="false"
    >
    <gradient
        android:type="radial"
        android:useLevel="false"
        android:gradientRadius="50dp"
        android:startColor="#e61010"
        android:centerColor="#38df0e"
        android:endColor="#d7da08"/>
</shape>

三、BitmapDrawable

   BitmapDrawable 是对bitmap的一种包装,可以设置它包装的bitmap在BitmapDrawable区域内的绘制方式,如平铺填充、拉伸填充或者保持图片原始大小,也可以在BitmapDrawable区域内部使用gravity指定的对齐方式。

在xml文件中使用bitmap作为根节点来定义BitmapDrawable。

 下面的xml代码定义一个BitmapDrawable,同时设置了BitmapDrawable的tileMode 属性为repeat,通过这样设置会使用小图片在水平和竖直方向做镜面平铺效果。

[代码]xml代码

<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_person"
    android:antialias="true"
    android:dither="true"
    android:filter="true"
    android:mipMap="false"
    android:gravity="center"
    android:tileMode="repeat">
</bitmap>

原图:效果图:

Bitmap的属性:

gravity属性详情:

  也可以使用Java代码实现相同的效果,等价的Java代码如下:
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_person);
BitmapDrawable mBitmapDrawable = new BitmapDrawable(mBitmap);
mBitmapDrawable.setTileModeXY(TileMode.MIRROR, TileMode.MIRROR);
mBitmapDrawable.setAntiAlias(true);
mBitmapDrawable.setDither(true);
mDrawable = mBitmapDrawable;

四、NinePatchDrawable (点九图)

NinePatchDrawable,“点九图”是Andriod平台的一种特殊的图片格式,文件扩展名为:.9.png。支持Android平台的手机类型很多,有多种不同的分辨率,很多控件的切图文件在被放大拉伸后,边角会模糊失真。在android平台下使用“点九”图片处理技术,可以将图片横向和纵向同时进行拉伸,以实现在多分辨率下的完美显示效果。点九图片在拉伸时仍能保留图像的渐变质感和圆角的精细度。

 Android SDK工具集提供了处理点九图片的工具,可以通过draw9patch.bat运行,通过这个工具可以很容易把普通的PNG图片处理成“点九”图片。从它的名字也很容易理解“点九”图的含义,其实相当于把一张PNG图分成了9个部分(九宫格),分别为4个角,4条边,以及一个中间区域,4个角是不做拉伸的,所以还能一直保持圆角的清晰状态,而2条水平边和2条垂直边分别只做水平和垂直拉伸,所以不会出现边框被拉粗的情况,只有中间用黑线指定的区域做拉伸,通过这种处理方式图片才不会失真。

自己生成 .9图:ic_launcher.9.png

 使用了*.9.png图片技术后,只需要采用一套界面切图去适配不同的分辨率,而且大幅减少安装包的大小。Android FrameWork在显示点九图片时使用了高效的优化算法,所示应用程序不需要专门做处理就可以实现图片拉伸自适应,减少了代码量和实际开发的工作量。 

  在xml文件中使用使用nine-patch作为根节点创建NinePatchDrawable。同时,也可以使用bitmap包装点九图片,android FrameWork会根据android:src属性设置的图片类型来生成对应的drawable。代码如下:

<?xml version="1.0" encoding="utf-8"?>
<nine-patch
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_launcher"
    android:dither="true">
</nine-patch>

 下面看一下原始点九图片以及拉伸之后的效果:

        最后,需要指出的是,Android虽然可以使用Java代码创建NinePatchDrawable,但是极少情况会那么做,主要的原因是由于Android SDK会在编译工程时对点九图片进行编译,形成特殊格式的图片。使用代码创建NinePatchDrawable时只能针对编译过的点九图片资源,对于没有编译过的点九图片资源都当做BitmapDrawable对待。在使用点九图片时需要注意的是,点九图只能适用于拉伸的情况,对于压缩的情况并不适用,如果需要适配很多分辨率的屏幕时需要把点九图做的小一点。

五、InsetDrawable

InsetDrawable 表示一个drawable嵌入到另外一个drawable内部,并且在内部留一些间距,这一点很像drawable的padding属性,区别在于 padding表示drawable的内容与drawable本身的边距,insetDrawable表示两个drawable和容器之间的边距。当控件需要的背景比实际的边框小的时候比较适合使用InsetDrawable。

总结一下:

  1. 对应inset标签
  2. 将其他Drawable内嵌到自身,并在四周留出间距
  3. View需要背景比自己实际区域要小的时候,可以使用insetlayer-list也可以实现该需求

下面的xml定义了一个四边边距都为20dip的InsetDrawable,代码如下:

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

</inset>

效果图:上边是引入insetdrawable,下边是原图:空白部分可以看出效果

<Button
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/inset_drawable"
    android:text="button"/>
<Button
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:background="@drawable/icon_fengjng"
    android:text="button"/>

六、ClipDrawable

ClipDrawable 是对一个Drawable进行剪切操作,可以控制这个drawable的剪切区域,以及相相对于容器的对齐方式,android中的进度条就是使用一个ClipDrawable实现效果的,它根据level的属性值,决定剪切区域的大小。

在xml文件中使用clip作为根节点定义ClipDrawable。

需要注意的是ClipDrawable是根据level的大小控制图片剪切操作的,官方文档的note中提到:The drawable is clipped completely and not visible when the level is 0 and fully revealed when the level is 10,000。也就是level的大小从0到10000,level为0时完全不显示,为10000时完全显示。是用Drawable提供的setLevel(int level)方法来设置剪切区域。

方向:android:clipOrientation="vertical|horizontal"

          android:gravity="left|right|top|bottom|center"

xml代码:

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

</clip>

在MainActviity中用一个seekBar来控制ClipDrawable的level,调用的是它的setLevel()方法。最终可以让它显示不同的比例。

xml代码:

<ImageView
    android:id="@+id/iv_clip"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_marginTop="20dp"
    android:src="@drawable/clip_drawable"/>
<SeekBar
    android:id="@+id/seekbar"
    android:layout_marginTop="10dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

然后是Activity文件中:

ivClip = (ImageView) findViewById(R.id.iv_clip);
seekBar = (SeekBar) findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        int max = seekBar.getMax();
        double scale =(double) progress /(double) max;
        ClipDrawable drawable =(ClipDrawable) ivClip.getDrawable();
        drawable.setLevel((int) (10000*scale));
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
    }
});

最终效果图:

没办法录制gif图,看看别人的效果图吧:https://blog.csdn.net/briblue/article/details/53528837

七、ScaleDrawable

ScaleDrawable是对一个Drawable进行缩放操作,ScaleDrawable与ClipDrawable类似,可以根据设置的level值对drawable进行缩放,但与ClipDrawable不同的是,ScaleDrawable还可以根据设置android:scaleWidthandroid:scaleHeight进行相应百分比的缩放。

在xml文件中使用scale作为根节点来创建RotateDrawable。

元素: 
<scale>定义一个ScaleDrawable,必须作为根元素。

  • android:drawable Drawable 资源。必须的。引用一个drawable资源。
  • android:scaleHeight 缩放的高度,以百分比的方式表示drawable的缩放。形式例如:100%,12.5%。
  • android:scaleWidth 缩放的宽度,以百分比的方式表示drawable的缩放。形式例如:100%,12.5%。
  • android:scaleGravity 指定缩放后的gravity的位置。必须是下面的一个或多个值(多个值之间用”|”分隔) 
    • top 将这个对象放在容器的顶部,不改变其大小。
    • bottom 将这个对象放在容器的底部,不改变其大小。
    • left 将这个对象放在容器的左部,不改变其大小。默认值。
    • right 将这个对象放在容器的右部,不改变其大小。
    • center_vertical 将对象放在垂直中间,不改变其大小。
    • fill_vertical 如果需要的话,该对象的垂直尺寸将增加,以便完全填充它的容器。
    • center_horizontal 将对象放在水平中间,不改变其大小。
    • fill_horizontal 如果需要的话,该对象的水平尺寸将增加,以便完全填充它的容器。
    • center 将对象放置在其容器的中心和水平轴的中心位置,而不改变它的大小。
    • fill 如果需要的话,该对象的水平和垂直方向的大小将增加,使得完全填充它的容器。
    • clip_vertical 可以设置为在其容器边界上的顶部和/或底部边缘的附加选项。该剪辑是基于垂直gravity:一个顶部gravity剪辑的底部边缘,底部重力剪辑的顶部边缘,既不剪辑两个边。
    • clip_horizontal 与clip_vertical类似,只是剪辑是基于水平gravity。

drawable:xml代码:(缩放各设为50%)

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

然后在layout中使用:

<ImageView
    android:id="@+id/iv_scale"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:src="@drawable/scale_drawable"/>

但是如果我们直接运行,发现并没有显示图片,查看ScaleDrawable的源码,发现draw()方法有判断getLevel() != 0才绘制。而我们在没有setLevel()时,默认getLevel()都是0。

所以如果我们想正常显示图片,还需要设置drawable的level。如下:

ivScale = (ImageView) findViewById(R.id.iv_scale);
ScaleDrawable drawable = (ScaleDrawable) ivScale.getDrawable();
drawable.setLevel(1);

ScaleDrawable的level为0,不可见。为10000时,不缩放。我们一般设置level为1,这样,图片就会根据xml中的android:scaleWidth和android:scaleHeight进行相应的缩放了。例如我们设置长宽缩放比例为50%,那么图片长和宽都是原来的一倍,图片大小实际是原来大小的四分之一。 

效果如下:上面是设置缩放之后的,下面是原图,图片变为原来的1/4.

八、 RotateDrawable

  RotateDrawable 是对一个Drawable进行旋转操作,可以根据level属性控制这个drawable旋转角度,也可以设置相对于它所在容器的对齐方式。

在xml文件中使用rotate作为根节点来定义RotateDrawable.

drawable下-xml代码:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/icon_fengjng"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:visible="true">

    <!-- android:drawable ===Drawable 资源。必须的。引用一个drawable资源。-->
    <!--android:fromDegrees == 整形。  从多少的角度开始旋转-->
    <!--android:toDegrees == 整形。  到多少的角度结束旋转-->
    <!--android:pivotX == 百分比。  旋转的中心在图片X轴的百分比-->
    <!--android:pivotY == 百分比。  旋转的中心在图片Y轴的百分比-->
    <!--android:visible == Boolean。是否可见。-->
</rotate>

这里的pivotY、pivotX分别代表旋转中心的位置,50%代表drawable的中心为旋转中心。toDegrees代表最大可以旋转的角度。在代码中是通过level值确定的,这两个值之间存在对应关系。如果设置最大旋转角度为180,那么Level=10000代表的就是旋转180度,5000代表旋转90度,如果最大旋转角度设置为270度,那么level=5000,就代表要旋转135度。可以自己尝试一下!!!(都是顺时针旋转)。
借鉴:https://blog.csdn.net/u011043551/article/details/61619282

layout使用 里xml代码:

<ImageView
    android:id="@+id/iv_rotate"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_marginTop="20dp"
    android:scaleType="fitXY"
    android:background="@color/colorAccent"
    android:src="@drawable/rotate_drawable"/>

在这里我将ImageView的背景设置为红色,drawable设置为图片显示来源,通过实例你就会发现,旋转的并不是imageView,仅仅只是drawable旋转了,然后再将旋转后的drawable重新输入到ImageView中。有背景色对比显得更清楚。。。

acticity里代码:

private boolean isRotating = false;
private static final int update_rotate = 100;
private RotateDrawable rotateDrawable;

private Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case update_rotate:
                int level = rotateDrawable.getLevel();
                if(level >= 10000){
                    timer.cancel();
                    rotateDrawable.setLevel(0);
                } else {
                    rotateDrawable.setLevel(level +100);
                }
                break;
        }
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_drawable);
    
    ivRotate = (ImageView) findViewById(R.id.iv_rotate);
    rotateDrawable = (RotateDrawable) ivRotate.getDrawable();
    rotateDrawable.setLevel(0);

    ivRotate.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            isRotating = true;
            if(isRotating){
                timer.start();
            }
        }
    });
}

定时器:

private CountDownTimer timer = new CountDownTimer(Integer.MAX_VALUE,60) {
    @Override
    public void onTick(long millisUntilFinished) {
        mHandler.sendEmptyMessage(update_rotate);
    }

    @Override
    public void onFinish() {
        isRotating = false;
    }
};

通过点击图片,开启定时器:在代码中通过定时器和handler实现UI刷新。

效果图借鉴:

九、AnimationDrawable

AnimationDrawable 对应于Android中的帧动画,就是把一系列的drawable按照一定的顺序,一帧一帧的播放,并且可以使用android:oneshot属性设置是否循环播放。android:oneshot 列表属性设置为true,它将循环一次,然后停止并保持最后一帧。如果它设置为false,则动画将循环。

在xml文件中使用animation-list作为根节点定义AnimationDrawable,使用item设置需要播放的每一帧使用的drawable资源,以及每一帧持续的时常。

下面定义一个包含五帧的AnimationDrawable,循环播放,帧间隔为300毫秒,代码如下

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@drawable/icon_fengjng1"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng2"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng3"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng4"
        android:duration="300"/>
    <item android:drawable="@drawable/icon_fengjng5"
        android:duration="300"/>
</animation-list>

layout使用:

<ImageView
    android:id="@+id/iv_anim"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:src="@drawable/anim_drawable"/>

activity调用AnimationDrawable的 .start() 播放动画:

ivAnim = (ImageView) findViewById(R.id.iv_anim);
animDrawable = (AnimationDrawable) ivAnim.getDrawable();
animDrawable.start();

需要注意的是,当我们在Activity的oncreate方法中调用start方法时会没有任何效果,那是因为view还没有初始化完成,无法播放动画,所以需要使用handler来延迟播放动画,具体实现代码如下:

ivAnim = (ImageView) findViewById(R.id.iv_anim);
animDrawable = (AnimationDrawable) ivAnim.getDrawable();
//使用Handler
Handler animHandler = new Handler();
//调用PostDelay()方法去执行,最后的300表示每隔300重新循环执行一次,可以理解成定时器
animHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        animDrawable.start();

    }
},1000);

效果借鉴别人图片:

十、LayerDrawable

LayerDrawable 管理一组drawable,每个drawable都处于不同的层,当它们被绘制的时候,按照顺序全部都绘制到画布上。虽然这些drawable会有交差或者重叠的区域,但是它们是位于不同的层,彼此之间不会影响。

在xml文件中使用layer-list作为根节点来定义LayerDrawable,通过item子节点定义每一层的drawable,layer-list没有属性节点,只包含item子节点。它表示一种层次化的Drawable集合,通过将不同的Drawable放置在不同的层上面达到一种叠加的效果。

其中 可以包含多个item,每个item表示一个Drawable

        item中可以通过android:drawable直接引用资源,如:<item android:drawable="@drawable/layer1" />

   android:top等表示Drawable相当于View上下左右的偏移量

drawable下xml代码实现 文本输入框:

<?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="@color/colorAccent"/>
            </shape>
        </item>

        <item
            android:bottom="6dp">
            <shape android:shape="rectangle">
                <solid android:color="#fff"/>
            </shape>
        </item>

        <item
            android:bottom="1dp"
            android:left="1dp"
            android:right="1dp">
            <shape android:shape="rectangle">
                <solid android:color="#fff"/>
            </shape>

        </item>

</layer-list>

使用:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="15dp"
    android:hint="请输入文字"
    android:background="@drawable/layer_drawable"/>

效果图:

十一、LevelListDrawable

对应于level-list标签
拥有多个item,每个item都有maxLevel和minLevel
Level的范围为0~10000
给定level后,会按从上至下的顺序匹配,直到找到范围合适的Drawable,并返回
item的level一定要降序或者升序
调用View的getBackground获得Drawable对象,并调用setLevel设置等级level
ImageView的setImageLevel()能快速指定src引用的Drawable的Level
LevelListDrawable是根据level改变,选择不同的Drawable,能用于实现进度条、音量调节等等

LevelListDrawable的使用:

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/icon_fengjng"
        android:minLevel="0"
        android:maxLevel="100"/>
    <item android:drawable="@drawable/ic_person"
        android:minLevel="101"
        android:maxLevel="200"/>
</level-list>

layout布局:

<Button
    android:id="@+id/btn_fengjing"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:text="风景"/>
<Button
    android:id="@+id/btn_person"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:text="人物"
    />
<ImageView
    android:id="@+id/iv_level"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:src="@drawable/level_drawable"
    />

activity使用:

    btnScenery = (Button) findViewById(R.id.btn_fengjing);
    btnPerson = (Button) findViewById(R.id.btn_person);
    ivLevel = (ImageView) findViewById(R.id.iv_level);
    ivAnim.setImageLevel(50);
    btnScenery.setOnClickListener(this);
    btnPerson.setOnClickListener(this);

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.btn_fengjing:
            ivLevel.setImageLevel(50);
            break;
        case R.id.btn_person:
            ivLevel.setImageLevel(150);
            break;
    }

}

效果图:默认风景图,点击后变为人物,再次点击风景按钮,又变回风景,ImageView根据level值来查找显示哪张图片:

十二、StateListDrawable:

 StateListDrawable管理一组drawable,每一个drawable都对应着一组状态,状态的选择类似于java中的switch-case组合,按照顺序比较状态,当遇到匹配的状态后,就返回对应的drawable,因此需要把最精确的匹配放置在最前面,按照从精确到粗略的顺序排列。
        StateListDrawable在Android中使用的非常广泛,所有控件的背景基本上都使用了StateListDrawable,比如按钮就具有很多状态,按下状态、选中状态、默认状态、禁用状态等等,像这样在不用的状态下显示效果不一样的时候,就是需要使用StateListDrawable的时候。

在xml文件中使用selector作为根节点来定义StateListDrawable,并使用item定义不同状态下的drawable。定义如下XML:

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize="false" //StateListDrawable的固有大小是否根据状态而改变,默认false=根据状态而改变
    android:dither="true"        //是否开启抖动-让高质量图片在低质量屏幕上依旧效果好,默认true开启
    android:variablePadding="false" //padding是否根据状态的改变而改变,不建议开启(false)
    >
    <item android:state_pressed="true"  //Button被按下后却没有松开的状态
        android:drawable="@color/colorAccent"/>
    <item android:state_focused="true"  //View获取了焦点
        android:drawable="@color/colorPrimary"/>
    <item android:state_selected="true" //用户选择了View
        android:drawable="@color/colorPrimary"/>
    <item android:state_checked="true" //用户选中了View,一般用于CheckBox这类在选中和没有选中状态之间切换的View
        android:drawable="@drawable/ic_launcher_background"/>
    <item android:state_enabled="true" //View处于可用状态
        android:drawable="@drawable/ic_launcher_foreground"/>
    <item android:drawable="#FFFFFF"/> //默认Drawable: 按顺序向下匹配,需要放在最下方,因为可以匹配任何状态
</selector>

Drawable的使用:

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

    <!--这个是输入框边框变色-->
    <item android:state_window_focused="false">
        <shape android:shape="rectangle">
            <solid
                android:color="#FFFFFFFF"/>
            <corners
                android:radius="3dp"/>
            <padding
                android:left="10dp"
                android:right="10dp"/>
            <stroke
                android:width="1dp"
                android:color="#BDC7D8"/>
        </shape>
    </item>

    <item android:state_focused="true" >
        <shape android:shape="rectangle" >
            <solid
                android:color="#FFFFFFFF"/>
            <corners
                android:radius="3dp"/>
            <padding
                android:left="10dp"
                android:right="10dp"/>
            <stroke
                android:width="1dp"
                android:color="#cf1b18"/>
        </shape>
    </item>
</selector>

layout:文件

<EditText
    android:id="@+id/btn_selector_1"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_gravity="center_horizontal"
    android:hint="请输入信息"
    android:layout_margin="15dp"
    android:singleLine="true"
    android:layout_marginTop="20dp"
    android:background="@drawable/selector_drawable"/>

效果图:

猜你喜欢

转载自blog.csdn.net/hanxiongwei/article/details/86078836
今日推荐