【总结】Drawable的用法,shape以外的部分
drawable 文件夹中,最常用的文件其实只有三种,分别是shape,selector,跟9patch图。
鉴于篇幅原因,shape单独拿出来写,剩余的包括selector,9patch图在内的六七种文件类型合成一篇来写。
BitmapDrawable
想不到吧,最基本的图片也能包一层xml文件来用,但这一层xml当然不是白写的,它能提供更强大的图片属性支持。
比如它最大的作用是,当把图片作为背景图使用的时候,不只有拉伸一种填充方式。
<?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="@mipmap/ic_android"
android:tileMode="disabled" />
<!--
antialias 抗锯齿功能,会使图片变得平滑,推荐开启,虽说会降低图片的清晰度,但是这个可以忽略
dither 图片防失真,推荐开启。防止屏幕支持的色彩模式比图片自身的色彩模式差时,图片失真
filter 开启过滤效果,推荐开启。当图片被拉伸或者压缩的时候,可以保证较好的显示效果。
gravity 图片定位选项,比较多,下文细说。
mipmap 是一种图像相关的处理技术,叫做纹理映射,默认false,平时不常用。
src 是图片资源id,这个必须有
tileMode 这个是图片的平铺方式,有一下四个选项,disable clamp repeat mirror
-->
gravity 可用属性以及含义 | |
---|---|
top | 将图片置顶,大小不变 |
bottom | 将图片置底,大小不变 |
left | 将图片放在控件左侧,大小不变 |
right | 将图片放在控件右侧,大小不变 |
center_vertical | 使图片垂直居中,大小不变 |
fill_vertical | 使图片在垂直方向上填充控件 |
center_horizontal | 使图片水平居中,大小不变 |
fill_horizontal | 使图片在水平方向上填充控件 |
center | 将图片置于中心位置,大小不变 |
fill | 使图片完全填充控件,这个是默认值 |
clip_vertical | 当控件垂直大小小于图片大小时,图片垂直方向剪裁,单独使用时,图片默认居中 |
clip_horizontal | 当控件水平大小小于图片大小时,图片水平方向剪裁,单独使用时,图片默认居中 |
需要注意的是,gravity只有当tileMode属性为disable时,才会生效。
而tileMode 属性的 repeat mirror 属性在做纹理背景时,非常实用。
tileMode 属性其他三个选项的效果如下图,其中ImageView的宽高属性均为填充。

NinePatchDrawable
又被称作是.9图或者9Patch图,开发中很实用的一个图片类型,可以降低我们卡发人员的适配难度。最常见的使用场景是对话框的框体。
9Patch图也可以加一层xml文件来使用,但是相比较与普通图片的极大增强,9Patch图只能增加一个 dither 图片防失真的属性,因此平时使用中我们都会直接使用。
9Patch图的边框线有两种,一种是黑色线,左侧,上侧两部分的黑线表示可拉伸区域,在View与图片大小不符合的时候,这两部分会拉伸以适应View的大小。
右侧,下侧部分黑线表示可显示区域,就是说,假设这个9Patch图是用作TextView的背景图使用,文字只会显示在右侧,下侧黑线重叠区域,类似于shape的Padding,但是可以被TextView的padding属性覆盖。
9Patch图还有一种红色的线,我没有使用过,也不明白是做什么用的,若您知道,请告诉我,感激不尽。
做9Patch图我比较喜欢将其重命名为xxx.9.png之后直接复制到drawable文件夹中,然后使用android studio 自带的工具对其进行画线,直接画线为黑色线,按住shift为擦除,按住ctrl为红色线,并且通过实时预览功能来确定是否为我想要的样子。不要使用任何插件/工具来完成这个步骤,太麻烦没必要。
StateListDrawable
这也是常用文件的一种,对应于<selector>标签的xml文件。
<?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">
<!--
selector的特性是会随着状态的改变而切换到具体的drawable
constantSize,表明切换到具体的drawable时,其大小是否会保持固有大小,默认为false
true,表明保持固有大小了,为所有drawable的固有大小的最大值
false,表明不保持固有大小,每切换到具体的drawable时使用当前drawable的大小
dither,图片防失真,默认为true
variablePadding,表明padding是否保持固有大小,类似于constantSize,默认为false
true,表明保持固有大小了
false,表明不保持固有大小
-->
<item android:drawable="@drawable/ic1"
android:state_checkable="true"
android:state_checked="true"
android:state_enabled="true"
android:state_focused="true"
android:state_pressed="true"
android:state_selected="true"/>
</selector>
selector中,item的状态一共有17种,选取常用的6个说明其含义
item的状态以及含义 | |
---|---|
state_checkable | 表示是否可选中,常见于CheckBox这种选择器中 |
state_checked | 表示是否被选中,常见于CheckBox这种选择器中 |
state_enabled | 表示是否处于可用状态 |
state_focused | 表示是否获取了焦点 |
state_pressed | 表示是否被按下 |
state_selected | 表示是否被选择 |
PS:平时开发时,我们常常会使用<selector>标签来实现不同状态时,显示不同图片的效果,但这是很不专业的一个写法,虽然说这么写也可以达到我们的预期,但是稍有不慎却会导致程序显示异常,严重情况甚至会崩溃。对于这种效果,我推荐使用<level-list>标签来实现。
LevelListDrawable
对应于<level-list>标签,它表示一个drawable的集合,其中每一个drawable对应一个或者多个等级,我们通过设置View的等级来切换drawable。
<level-list>标签是安卓推荐的设置图片集合的一个方式,而不是使用<selector>标签。
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@mipmap/ic_1"
android:maxLevel="0"
android:minLevel="10" />
<item
android:drawable="@mipmap/ic_2"
android:maxLevel="11"
android:minLevel="20" />
</level-list>
之后通过设置level属性来切换图片。
ImageView可以使用setImageLevel()来切换其src对应的图片,
其他View背景图统一使用getBackground().setLevel()来切换背景图片。
imageView.setImageLevel(0);
view.getBackground().setLevel(0);
使用的时候一定要保证每个<item>标签之间的level范围不重合,level的值不能为负数,且顺序要么为升序,要么为降序,不能为乱序。为View设置level值时,有且只有一个<item>标签与其对应,否则会出现显示效果达不到预期的情况,甚至不会显示。
平时使用的时候,可以忽略<item>标签中的minLevel属性,将其简写为
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@mipmap/ic_1"
android:maxLevel="1" />
<item
android:drawable="@mipmap/ic_2"
android:maxLevel="2" />
</level-list>
TransitionDrawable
对应于<transition>标签,用于实现两张图片淡入淡出的效果,可用于ImageView的资源图片,或者其他View的背景。
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/bg1" />
<item android:drawable="@mipmap/bg2" />
</transition>
<!--item的属性包括,宽高以及左右边距,因为都是常见的属性,所以不做解释了-->
<item
android:bottom="10dp"
android:height="100dp"
android:width="100dp"
android:drawable="@mipmap/bg1"
android:left="10dp"
android:right="10dp"
android:top="10dp" />
将TransitionDrawable设置为View的背景或者ImageView的显示图片后,可以通过以下方式获取到该TransitionDrawable,并且进行淡入淡出动画。
transitionDrawable = (TransitionDrawable) view.getBackground();
transitionDrawable = (TransitionDrawable) imageView.getDrawable();
transitionDrawable.startTransition(1000);
transitionDrawable.reverseTransition(1000);
InsetDrawable
对应于<inset>标签,可以对一张图片增加上下左右的padding,一般用于背景比实际显示的区域小的时候。
相对于<layer-list>标签,<inset>标签看起来更加简单,不过实现这种效果时我比较喜欢用<layer-list>标签来实现。
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@mipmap/bg1"
android:insetBottom="20dp"
android:insetLeft="20dp"
android:insetRight="20dp"
android:insetTop="20dp">
<!--使用时,可以直接指定drawable,或者内嵌其他Drawable文件,比如shape-->
<shape android:shape="rectangle"></shape>
</inset>
为View设置背景时,View的padding会默认为<inset>标签内写入的内边距值,此时重新指定当前View的padding,便可达到预期。

还有两个
他们分别是
ScaleDrawable
对应于<scale>标签,用来对一张图片进行缩放。
ClipDrawable
对应于<clip>标签,用来实现对一张图片的剪裁。
由于通过它对图片的剪裁效果并不直观,不如让UI同学切图来得快,每次用完都会让UI同学一顿锤,所以我不怎么喜欢用,此处不表。
个人理解,难免有错误纰漏,欢迎指正。转载请注明出处。