Android开发Android开发Android开发经验谈

Android的Drawable

2018-11-20  本文已影响14人  一个有故事的程序员

导语

Drawable表示的是一种可以在Canvas上进行绘制的抽象概念,它的种类有很多,最常见的就是颜色和图片。优点:使用简单,比自定义View成本低很多,非图片类型的Drawable占用空间较小。本章中,首先描述Drawable的层次关系,接着介绍Drawable的分类,最后介绍自定义Drawable相关的知识。

主要内容

具体内容

Drawable简介

Drawable有很多种,都表示图像的概念,但不全是图片,通过颜色也可以构造出各式各样的图像效果。实际开发中,Drawable常被用来作为View的背景使用。Drawable一般是通过XML来定义的,Drawable是所有Drawable对象的基类。

Drawable的内部宽、高这个参数比较重要,通过getIntrinsicWidth/getIntrinsicHeight这两个方法获取。但并不是所有Drawable都有宽高;图片Drawable的内部宽/高就是图片的宽/高,但是颜色形成的Drawable并没有宽/高的概念。

Drawable的分类

常见的有BitmapDrawable、ShapeDrawable、LayerDrawable以及StateListDrawable等。

BitmapDrawable

表示的就是一张图片,可以直接引用原始图片即可,也可以通过XML描述它,从而设置更多效果。

<?xml version="1.0" encoding="utf-8"?>
<bitmap / nine-patch
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:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />

属性分析:

NinePatchDrawable:
表示一张.9格式的图片,它和BitmapDrawable都表示一张图片。用XML描述的方式也和BitmapDrawable一样。在bitmap标签中也可以使用.9图。

ShapeDrawable

可以理解为通过颜色来构造的图形,可以是纯色或渐变的图形。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
    android:bottomLeftRadius="10dp"
    android:bottomRightRadius="10dp"
    android:radius="5dp"
    android:topLeftRadius="10dp"
    android:topRightRadius="10dp" />
 
<gradient
    android:angle="0"
    android:centerColor="#cccccc"
    android:centerX="100"
    android:centerY="20"
    android:endColor="#abcdef"
    android:gradientRadius="100dp"
    android:startColor="#000000"
    android:type="linear"
    android:useLevel="false" />
 
<solid android:color="#cccccc" />
 
<stroke
    android:width="1dp"
    android:color="#cccccc"
    android:dashGap="2dp"
    android:dashWidth="50dp" />

属性分析:

LayerDrawable

它表示一种层次化的Drawable集合,通过将不同的Drawable放置在不同层后达到一种叠加效果。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:id="@+id/res_haimei1"
    android:bottom="10dp"
    android:drawable="@mipmap/haimei1"
    android:left="10dp"
    android:right="10dp"
    android:top="10dp" />
 
<item
    android:id="@+id/res_icon"
    android:width="30dp"
    android:height="30dp"
    android:drawable="@mipmap/ic_launcher"
    android:gravity="center" />
StateListDrawable

对应<selector>标签。它表示Drawable集合,每个Drawable对应View的一种状态,这样系统就会根据View的状态来选择合适的Drawable。主要用于设置可点击View的背景。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" 
android:constantSize="false" 
android:dither="true" 
android:variablePadding="false">
<item android:drawable="@mipmap/ic_launcher" android:state_pressed="true" />
<item android:drawable="@mipmap/haimei1" android:state_pressed="false" />

属性分析:

view的常见状态:

默认的item一般放在最后并且不添加任何状态,这样当系统在之前的item无法选择的时候,就会匹配默认的item,因为item的默认状态不附带任何状态,所以它可以适配任何状态。

LevelListDrawable

对应<level-list>标签。同样表示Drawable集合,集合中的每个Drawable都会有一个等级的概念,根据等级不同来切换对于的Drawable。当它作为View的背景时,可以通过Drawable的setLevel方法来设置不同的等级从而切换具体的Drawable。level的值从0-10000,默认为0。

<?xml version="1.0" encoding="utf-8"?>
 <level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:maxLevel="0" android:drawable="@drawable/ic_playmethod_normal" />
    <item android:maxLevel="1" android:drawable="@drawable/ic_playmethod_repeat_list" />
    <item android:maxLevel="2" android:drawable="@drawable/ic_playmethod_repeat_one" />
    <item android:maxLevel="3" android:drawable="@drawable/ic_playmethod_random" />
</level-list>
TransitionDrawable

对应<transition>标签。用来实现两个Drawable之间淡入淡出的效果。

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/haimei2" />
    <item android:drawable="@mipmap/haimei3" />
</transition>
TransitionDrawable drawable = (TransitionDrawable) imageView.getBackground();
drawable.startTransition(1000);

startTransition和reverseTransition方法实现淡入淡出的效果以及它的逆过程。

InsetDrawable

对应于<inset>标签。它可以将其他Drawable内嵌到自己当中,并可以在四周留下一定的间距。当一个View希望自己的背景比自己的实际区域小的时候,可以采用InsetDrawable来实现。通过LayerDrawable也可以实现。

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@mipmap/haimei1"
    android:insetBottom="10dp"
    android:insetLeft="10dp"
    android:insetRight="10dp"
    android:insetTop="10dp">
    <shape android:shape="rectangle">
        <solid android:color="#abcdef" />
    </shape>
</inset>

其中,inset中的shape距离view边界为10dp。

ScaleDrawable

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

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@color/blue"
    android:level="1"
    android:scaleGravity="center"
    android:scaleHeight="20%"
    android:scaleWidth="20%" />

其中,android:scaleGravity属性相当于gravity属性。android:scaleHeight/scaleWidth 表示Drawable的缩放比例。
缩放公式: w -= (int) (w * (10000 - level) * mState.mScaleWidth / 10000)
可见,level越大,Drawable看起来越大;scaleHeight/scaleWidth越大,Drawable看起来越小。注意的是,level设置为0时,Drawable不可见。level不应超过10000。

ClipDrawable

ClipDrawabe对应于<clip>标签,他可以根据自己当前的等级(level)来裁剪一个Drawable,裁剪方向可以通过Android:clipOrientation和android:gravity两个属性共同控制。

<?xml version="1.0" encoding="utf-8"?> 
<clip xmlns:android="http://schemas.android.com/apk/res/android" 
android:clipOrientation="vertical\horizontal" 
android:drawable="@drawable/bitmapdrawable" 
android:gravity="bottom|top|left|right|center|fill|center_vertical|center_horizontal|fill_vertical|fill_horizontal|clip_vertical|clip_horizontal" />

clipOrientation表示裁剪方向。gravity需要和clipOrientation一起才能发挥作用。
使用步骤:

  1. 定义ClipDrawable。
  2. 布局文件引用。
  3. 代码控制level。
 ImageView imageClip = (ImageView) findViewById(R.id.image_clip); 
 ClipDrawable drawable = (ClipDrawable) imageClip.getDrawable(); 
 drawable.setLevel(5000);

level=0的时候,表示完全裁剪,level=10000的时候表示完全不裁剪,level=5000的时候表示裁剪了一半。即等级越大,裁剪的区域越小。

自定义Drawable

在前面,我们分析了View的工作原理,系统会调用Drawable的draw方法绘制view的背景。所以我们可以通过重写Drawable的draw方法来自定义Drawable。但是,通常我们没必要自定义Drawable,因为自定义Drawable无法在XML中使用。只有在特殊情况下可以使用自定义Drawable。
圆形自定义Drawable demo,半径随着view的变化而变化

更多内容戳这里(整理好的各种文集)

上一篇 下一篇

猜你喜欢

热点阅读