Android开发中,和布局文件对应 View 一样,Drawable 文件也对应着一个类--Drawable。
如下面两个表所示。
节点 | View 类 | 类型 |
---|---|---|
LinearLayout | android.widget.LinearLayout | ViewGroup |
TextView | android.widget.TextView | View |
Button | android.widget.Button | View |
... | ... | ... |
假设在布局文件的根布局使用了 LinearLayout , 里面包含了一个 TextView 和 一个 Button,随后在 Activity 中使用 setContentView(R.layout.main);
或者使用 LayoutInflater.from(mContext).inflate(R.id.main, null, false);
来加载 view,Android 会把布局文件中的每个节点都转换对应的类,组合成一个新的 view,用在 Activity 背景上或者得到这个 view做其他的操作。
下面来看今天的主题---Drawable,以布局文件来类比。
序号 | 节点 | Drawable 具体子类 | 说明 |
---|---|---|---|
1 | [bitmap] | BitmapDrawable | 对bitmap的封装 |
2 | [color] | ColorDrawable | 把颜色封装成可以显示的Drawable |
3 | [shape] | ShapeDrawable | 绘制基础的形状图形,最常用的Drawable之一,可用于定义圆角、渐变色、圆环等效果 |
4 | [selector] | StateListDrawable | 表示一组有状态的图像的集合,可用于给button等设置点击和正常状态下的图片 |
5 | [level-list] | LevelListDrawable | 表示一组有等级的图像的集合 |
6 | [layer-list] | LayerDrawable | 表示图层 |
7 | [nine-patch] | NinePatchDrawable | 对.9.png的封装 |
8 | [clip] | ClipDrawable | 对drawable裁剪 |
9 | [inset] | InsetDrawable | 用距离边框的距离表示drawable大小 |
10 | [ripple] | RippleDrawable | 波纹点击效果,API21以上 |
下面看怎样在xml文件中使用这些 Drawable,当然和布局文件中的 view 一样,我们也可以使用java代码来创建这些对象,但是我们一般不这样做,就像我们不会用java代码创建一个复杂的布局一样。
一、BitmapDrawable
在 drawable 文件夹下创建一个xml文件,修改 <selector/>
根节点为 <bitmap/>
,并且增加 src 属性,像下面这样:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_launcher">
</bitmap>
这样,我们就可以在文件文件中设置 view 的背景 android:background="@drawable/bitmap"
,bitmap 就这么简单,我们一般也不会这样来用,使用的话也是配合别的 Drawable,用于包装图片资源,比如在 StateListDrawable(selector节点)下,对应每一个drawable 设置不同的 BitmapDrawable。
bitmap 节点下不能再包含节点。
所有的设置都通过属性来完成。
下表列出所有的属性供参考。
属性 | 参数类型 | 说明 |
---|---|---|
android:src | Drawable resource | 显示的图片,不能为color等,只能为图片资源 |
android:alpha | float | 透明度0-1,值越小,越透明 |
android:antialias | boolean | 是否开启抗锯齿 |
android:autoMirrored | boolean | 设置图片是否需要镜像反转,当布局方向是RTL,即从右到左布局时才有用,API19以上 |
android:dither | boolean | 是否抖动 |
android:filter | boolean | 设置是否允许对图片进行滤波 |
android:gravity | center... | 图片对其方式,同布局文件中view的gravity属性 |
android:mipMap | boolean | 设置是否可以使用mipmap API18以上 |
android:tileMode | disabled、mirror、clamp、repeat | X、Y轴平铺方式, disabled(默认):不使用平铺;mirror:镜面;clamp:复制图片边缘的颜色来填充容器剩下的空白部分;repeat:图片重复铺满 |
android:tileModeX | 同上 | X轴平铺方式,参数意义同上 |
android:tileModeY | 同上 | Y轴平铺方式,参数意义同上 |
android:tint | color | 给图片着色 |
android:tintMode | add、multiply、screen、src_atop、src_in、src_over | 着色模式 |
二、ColorDrawable
ColorDrawable 对应xml文件中的 <color/>
节点,同样在 drawable 文件夹下新建一个xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<color xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorAccent">
</color>
color 节点只有唯一一个也是必须的属性,android:color
使用color资源文件中的color赋值即可。同样没有子节点,最为简单的一个Drawable,把color 值转化为了Drawable对象,以便在其他需要Drawable的地方使用。
三、ShapeDrawable
使用 <shape/>
节点用来定义形状,可以定义矩形、椭圆、线、圆环四种类型的形状。shape 节点包含一些属性和子节点:
属性:
属性 | 参数类型 | 说明 |
---|---|---|
android:shape | rectangle、oval、line、ring | 定义形状的类型,rectangle(矩形)、oval(椭圆)、line(线)、ring(圆环)默认为矩形 |
android:innerRadius | int | 圆环内圆的半径 |
android:innerRadiusRatio | int | 内半径占整个Drawable宽度的比例,默认值为9 |
android:thickness | int | 圆环的厚度 |
android:thicknessRatio | int | 厚度占整个Drawable宽度比例,默认值为3 |
android:useLevel | boolean | 设置等级,配合LevelListDrawable使用时设置 |
android:visible | boolean | 设置是否可见 |
android:dither | boolean | 是否抖动 |
android:tint | color | 给图片着色 |
android:tintMode | add、multiply、screen、src_atop、src_in、src_over | 着色模式 |
子节点:
solid 填充色
表示形状的填充色,只有color一个属性:android:color
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/colorAccent"/>
</shape>
填充颜色的矩形.png
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorAccent"/>
</shape>
填充颜色的椭圆.png
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="50dp"
android:shape="ring"
android:thickness="10dp"
android:useLevel="false">
<solid android:color="@color/colorAccent"/>
</shape>
填充颜色的圆环.png
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<stroke
android:width="4dp"
android:color="@color/colorAccent"
android:dashGap="8dp"
android:dashWidth="4dp"/>
</shape>
线.png
corners 圆角
表示圆角的半径,对应有四个角的属性,和一个总体的属性
属性 | 参数类型 | 说明 |
---|---|---|
android:radius | int | 统一设置圆角半径 |
android:bottomLeftRadius | int | 设置左下角圆角半径 |
android:bottomRightRadius | int | 设置右下角圆角半径 |
android:topLeftRadius | int | 设置左上角圆角半径 |
android:topRightRadius | int | 设置右上角圆角半径 |
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:bottomLeftRadius="3dp"
android:radius="5dp"/>
<solid android:color="@color/colorAccent"/>
<size
android:width="30dp"
android:height="30dp"/>
</shape>
圆角.png
gradient 渐变色
表示渐变色,可以设置形状填充的颜色为渐变色
属性 | 参数类型 | 说明 |
---|---|---|
android:angle | int | 设置旋转的角度,45的倍数 |
android:startColor | color | 颜色变化的起始值 |
android:endColor | color | 颜色变化的结束值 |
android:centerColor | color | 中间的颜色 |
android:centerX | int | 渐变中心点的横坐标 |
android:centerY | int | 渐变的中心点的纵坐标 |
android:gradientRadius | int | 渐变的梯度,当android:type=”radial”有效 |
android:type | linear 、 radial 、 sweep | 渐变类别,linear(线性)为默认值,radial(径内渐变),sweep(扫描渐变) |
android:useLevel | boolean | 设置等级,配合LevelListDrawable使用时设置 |
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:type="sweep"
android:endColor="@color/colorAccent"
android:startColor="@color/colorPrimary"/>
<size
android:width="30dp"
android:height="30dp"/>
</shape>
渐变色.png
stroke 边框
表示边框。
属性 | 参数类型 | 说明 |
---|---|---|
android:color | color | 边框颜色 |
android:width | int | 边框宽度 |
android:dashGap | int | 边框虚线间隙大小 |
android:dashWidth | int | 边框虚线每个小节的宽度 |
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="2dp"
android:color="@color/colorAccent"
android:dashGap="2dp" // 和dashWidth一起设置,若不设置则为实线
android:dashWidth="3dp"/>
<size
android:width="30dp"
android:height="30dp"/>
</shape>
虚线边框.png
size 大小
设置背景大小,width和height俩属性。一般来说这个值不是shape的最终显示大小,因为shape作为背景时会根据View的大小而填充其背景,因此Shape的大小很多时候是View的大小决定的。
padding 内边距
表示内容或子标签边距,4个属性top、bottom、left、right,需要注意的是这个标签的作用是为内容设置与当前应用此shape的View的边距,而不是设置当前View与父元素的边距。
四、StateListDrawable
StateListDrawable 对应 drawable 文件夹下的xml文件的 <selector/>
节点,表示drawable集合。selector 可以包含不止一个 item 节点,每个 item 节点对应两类属性,一类只有一个 android:drawable
, 另一类是类似于 android:state_pressed
,表示当前所在view的状态,有按下、选择、获得焦点等十几种状态,需要注意不是每一个view都有这么多状态。
最常见的场景是给 Button 设置点击和正常状态下的drawable。
selector 节点 属性:
属性 | 参数类型 | 说明 |
---|---|---|
android:autoMirrored | boolean | 设置图片是否需要镜像反转 |
android:constantSize | boolean | 设置自身大小是否随着其状态改变而改变 |
android:enterFadeDuration | int | 状态改变时,新状态展示时的淡入时间,以毫秒为单位 |
android:exitFadeDuration | int | 状态改变时,新状态消失时的淡入时间,以毫秒为单位 |
android:variablePadding | boolean | padding是否随状态的改变而改变,默认false |
子节点 item 属性:
属性 | 参数类型 | 说明 |
---|---|---|
android:drawable | drawable | 对应drawable,可以为color、bitmap、shape等单一drawable |
android:android:state_xxx | boolean | 设置不同的状态 |
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/button_press"
android:state_pressed="true"/>
<item android:drawable="@color/button_norm"
android:state_pressed="false"/>
</selector>
子节点 item 还可以包含许多子节点,如bitmap、shape、color、动画相关的等,下面给出两个例子说明用法。
在布局文件中给view设置 android:background="@drawable/button_seleter"
即可,实现在点击view时显示不同的背景图,有点击的效果反馈。
这里需要注意一点:
如果上边所说的view是 Button 的话,直接可以看到效果,但是,实际开发中,我们可能要给 LinearLayout、TextView 设置点击效果,使用上面的方法是没有效果的。
解决方法:给这个 view 添加点击事件的监听。
上边代码中的 android:drawable
不只可以设置为color类型的drawable,还可以设置为bitmapDarwable、ShapeDrawable等,下面看一个圆角点击效果的例子。
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape>
<corners android:radius="10dp"/>
<solid android:color="@color/button_norm"/>
</shape>
</item>
<item android:state_pressed="true">
<shape>
<corners android:radius="10dp"/>
<solid android:color="@color/button_press"/>
</shape>
</item>
</selector>
设置在view上的效果为有圆角效果,并且按下的时候,背景后改变。
以上代码在 selector 节点下有两个 item 节点,item节点设置了是否点击的状态,并且包含了一个 shape 节点,作为对应状态下的drawable对象。
五、LevelListDrawable
LevelListDrawable 对应xml文件中的 <level-list/>
节点,表示一组由等级大小标志的 drawable,不同的等级可以为之设置不同的背景drawable。
此节点没有参数,只能包含不止一个的 item 子节点。
item 节点的属性:
属性 | 参数类型 | 说明 |
---|---|---|
android:drawable | drawable | 对应drawable,可以为color、bitmap、shape等单一drawable |
android:maxLevel | int | 设置等级范围的最大值 |
android:minLevel | int | 设置等级范围的最小值 |
<?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="20"
android:minLevel="11"/>
</level-list>
简单起见,使用 ColorDrawable 来设置对应的 android:drawable,有两种不同的背景,对应都有不同的等级范围。
设置给view 作为背景,像这样:android:background="@drawable/level"
。
在java代码中,获取到此view的 background,再设置其level属性的值,就会变为对应等级的背景。
boolean flag;
public void onClick(View v) {
if (flag) {
view.getBackground().setLevel(3);
} else {
view.getBackground().setLevel(13);
}
this.flag = !this.flag;
}
六、LayerDrawable
LayerDrawable 也表示 drawable 集合,对应xml文件中的<layer-list/>
节点,根据名称我们可以知道其中的每一个 drawable 都代表一个图层,新加入的 drawable 位于背景图片的最高图层。
item 的 android:drawable 属性也是可以设置为复杂的drawable的,方便起见,这里使用 colorDrawable。
属性 | 参数类型 | 说明 |
---|---|---|
android:opacity | transparent、translucent、opaque | 设置透明度:transparent透明、translucent半透明、opaque不透明 |
android:paddingXxx | int | 设置等级范围的最大值 |
子节点 item 属性,都是定位的属性,像height,width,gravity,bottom,top,left,right等。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="10dp"
android:drawable="@color/colorAccent"
android:left="10dp"
android:right="10dp"
android:top="10dp"
/>
<item
android:bottom="50dp"
android:drawable="@color/colorPrimary"
android:left="50dp"
android:right="50dp"
android:top="50dp"
/>
</layer-list>
效果如下:
七、NinePatchDrawable
NinePatchDrawable 是点九图的封装,xml文件中对应 <nine-patch/>
标签,属性和BitmapDrawable中属性的含义相同。
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/btn_bk"
android:dither="true"/>
八、ClipDrawable
ClipDrawable 代表可以裁剪的drawable,对应xml文件中的<clip/>
标签,通过当前设置的比例来裁剪Drawable,ClipDrawable的setLevel()方法可以控制显示比例,ClipDrawable的level值范围在[0,10000],level的值越大裁剪的内容越少,当level为10000时则完全显示,而0表示完全裁剪,不可见。
<clip/>
标签的属性:
属性 | 参数类型 | 说明 |
---|---|---|
android:drawable | drawable | 对应drawable,可以为color、bitmap、shape等单一drawable |
android:clipOrientation | horizontal、vertical | 裁剪的方向,horizontal水平、vertical垂直 |
android:gravity | right、top等 | 设置drawable所在位置,配合android:clipOrientation 属性一起用 |
android:gravity 可以设置下表所示的值:
属性 | 描述说明 |
---|---|
top | 将这个对象放在容器的顶部,不改变其大小。当clipOrientation 是”vertical”,裁剪从底部开始 |
bottom | 将这个对象放在容器的底部,不改变其大小。当clipOrientation 是”vertical”,裁剪从顶部开始 |
left | 将这个对象放在容器的左部,不改变其大小。当clipOrientation 是 “horizontal”,裁剪从drawable的右边(right)开始,默认值 |
right | 将这个对象放在容器的右部,不改变其大小。当clipOrientation 是 “horizontal”,裁剪从drawable的左边(left)开始 |
center | 将这个对象放在水平垂直坐标的中间,不改变其大小。当clipOrientation 是 “horizontal”裁剪发生在左右。当clipOrientation是”vertical”,裁剪发生在上下。 |
center_vertical | 将对象放在垂直中间,不改变其大小,如果clipOrientation 是 “vertical”,那么从上下同时开始裁剪 |
center_horizontal | 将对象放在水平中间,不改变其大小,clipOrientation 是 “horizontal”,那么从左右两边开始裁剪 |
fill | 填充整个容器,不会发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)。 |
fill_vertical | 垂直方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完) |
fill_horizontal | 水平方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完) |
clip_vertical | 附加选项,表示竖直方向的裁剪,很少使用 |
clip_horizontal | 附加选项,表示水平方向的裁剪,很少使用 |
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="horizontal"
android:drawable="@drawable/ic_launcher"
android:gravity="right">
</clip>
上边代码定义了一个 ClipDrawable 对象,设置进行水平方向裁剪,并且从左边开始裁剪。drawable为app启动图标。
在布局文件的view中使用像 android:background="@drawable/clip"
代码来使用上边定义的 ClipDrawable。
在java代码中,通过设置 ClipDrawble 的 level 属性的值,来进行图片背景的裁剪。
linearLayout = (LinearLayout) findViewById(R.id.lll);
linearLayout.getBackground().setLevel(5000); // 裁剪一半,0~10000
效果如下图:
九、InsetDrawable
InsetDrawable 用距离边框的距离表示drawable大小,比如我们需要让view的背景不是完全填充这个view,并且需要一定的距离,就可以使用 InsetDrawable 来完成。InsetDrawable 对应xml文件中的 <inset/>
标签。
属性:
属性 | 参数类型 | 说明 |
---|---|---|
android:drawable | drawable | 对应drawable,可以为color、bitmap、shape等单一drawable |
android:inset | dimen | 统一设置距离边框的距离 |
android:insetTop | dimen | 设置距容器上边的距离 |
android:insetBottom | dimen | 设置距容器下边的距离 |
android:insetLeft | dimen | 设置距容器左边的距离 |
android:insetRight | dimen | 设置距容器右边的距离 |
android:visible | boolean | 设置是否可见 |
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@color/colorAccent"
android:inset="10dp">
</inset>
十、RippleDrawable
RippleDrawable 可以在Android5.0 即 API21 以上实现波纹点击效果,对应xml文件中的 <ripple/>
标签。由于此标签必须在API21以上才可以使用,我们也不能设置 minSdkVersion
为21,毕竟要适配更多的API版本,我们可以在建立一个 drawable-v21
的文件夹,在里面新建一个xml文件即可。
在Android studio中,就更方便了,选中 Drawable 文件夹--->右键--->选择new--->单击 Drawable resource file 选项,就来到了如下对话框:
填写文件名,选择最后一个Version,单击中间的表示向右的按钮,填写21,点击ok,就会自动生成对应文件和新建文件。
<ripple/>
标签的属性:
属性 | 参数类型 | 说明 |
---|---|---|
android:color | color | 波纹的颜色,会覆盖在背景上 |
android:radius | dimen | 圆角,不太懂,设置大小效果都一样 |
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/gray">
<!--有界-->
<item
android:id="@android:id/mask"
android:drawable="@color/gray"/>
</ripple>
需要注意的是 android:id="@android:id/mask"
,没有设置时,是无边界的波纹效果,添加后为有边界。
参考博文:
参考视频教程: