【Android - 进阶】之Drawable简介
Drawable是什么?Android给我们的解释是:“A general abstraction for 'something that can be drawn'.”,翻译过来就是:对于可以绘制的东西的一个抽象。也就是说,Drawable是一种可以在Canvas上绘制的东西。在Android开发中,Drawable有两种用法,分别是作为View的背景以及作为ImageView中显示的内容。Android系统中为我们提供了很多种Drawable,这些Drawable大多都是在XML中使用,有些也可以在JAVA代码中写一些辅助代码。我们也可以自定义Drawable。本文主要讲解Android系统为我们提供的Drawable中的13种。
1、ColorDrawable
ColorDrawable 对应的XML顶层标签是 <color> ,代表的是一个纯色的Drawable,通常可以用来做分割线等View的背景。使用方法如下所示:
<?xml version="1.0" encoding="utf-8"?> <color xmlns:android="http://schemas.android.com/apk/res/android" android:color="@android:color/darker_gray" />
2、GradientDrawable
GradientDrawable 对应的XML顶层标签是 <shape> ,是开发中最常用的Drawable之一。通过GradientDrawable,我们可以实现圆角、渐变色、线条等特殊样式。一个使用GradientDrawable的示例代码如下:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="10.0dip" /> <gradient android:angle="270" android:centerColor="@color/colorPrimaryDark" android:endColor="@android:color/darker_gray" android:startColor="@color/colorAccent" android:type="sweep" /> <padding android:bottom="20.0dip" android:left="20.0dip" android:right="20.0dip" android:top="20.0dip" /> <stroke android:width="5.0dip" android:color="@color/colorAccent" android:dashGap="5.0dip" android:dashWidth="25.0dip" /> </shape>
通过上面的XML代码,我们可以得到一个圆角的、内边距20dp的、扫描式渐变色的、虚线边框的Drawable。GradientDrawable中常用的属性及子标签的详细介绍如下所示:
android:shape:设置整体的形状,可以是rectangle矩形、oval椭圆、line横线、ring圆环 <corners>:圆角 android:radius:统一设置四个角的圆角程度 android:topLeftRadius:设置左上角的圆角程度 android:topRightRadius:设置右上角的圆角程度 android:bottomLeftRadius:设置左下角的圆角程度 android:bottomRightRadius:设置右下角的圆角程度 <gradient>:渐变色 android:type:渐变色的类型,有linear线性渐变、radial发散渐变、sweep扫描渐变 android:startColor:渐变的起始颜色 android:centerColor:渐变的中心颜色 android:endColor:渐变的结尾颜色 android:angle:线性渐变属性,设置渐变的倾斜角度 android:gradientRadius:发散渐变属性,设置发散渐变的半径 android:centerX:发散渐变属性,设置发散渐变的圆心的X坐标 android:centerY:发散渐变属性,设置发散渐变的圆心的Y坐标 <padding>:内边距 android:left:shape中的内容距离shape左边界的距离 android:right:shape中的内容距离shape右边界的距离 android:top:shape中的内容距离shape上边界的距离 android:bottom:shape中的内容距离shape下边界的距离 <size>:大小 android:width:这个shape的宽度 android:height:这个shape的高度 <solid>:填充色 android:color:形状的填充色 <stroke>:线条 android:width:线条的粗细 android:color:线条的颜色 android:dashWidth:虚线线段的宽度 android:dashGap:虚线线段之间的间隙
上面代码的运行效果如下图所示:
3、StateListDrawable
StateListDrawable 对应的XML顶层标签是 <selector> ,也是开发中最常用的Drawable之一。通过这种Drawable,我们可以让一个View的背景在响应不同状态时显示为不同的样式。一个使用StateListDrawable的示例代码如下:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/ic_launcher" android:state_pressed="true" /> <item android:drawable="@mipmap/ic_launcher" android:state_focused="true" /> <item android:drawable="@mipmap/ic_launcher" android:state_selected="true" /> <item android:drawable="@mipmap/ic_launcher_round" /> </selector>
通过上面的代码,我们就为View设置了默认显示的状态和按压、选中、获取焦点等状态下显示的状态。StateListDrawable中几个常用状态解释如下:
android:state_pressed:按下状态
android:state_focused:获取了用户焦点的状态
android:state_selected:被用户选择的状态
android:state_checked:被用户选中的状态,适用于CheckBox等控件
android:state_enabled:可用状态
4、BitmapDrawable
BitmapDrawable 对应的XML顶层标签是 <bitmap> ,它的作用是加载一张图片,并对其进行一些性能、平铺模式等的处理。下面是一个使用BitmapDrawable的示例:
<?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="fill" android:src="@mipmap/image02" android:tileMode="mirror" />
通过上面的代码,我们不仅加载了一张图片资源,还设置了抗锯齿、抖动都性能调优,更设置了图片的平铺模式为镜像重复模式。BitmapDrawable中各种属性的详细解释如下:
src:图片的资源ID
antialias:抗锯齿,让图片变得平滑
dither:抖动,让高质量的图片在低质量的屏幕上能保持较好的显示效果
filter:过滤,当图片尺寸被缩放后,可以保持较好的显示效果
gravity:当图片尺寸小于容器尺寸时,对图片进行定位
tileMode:平铺模式,默认是disabled,还可以有一下值:
clamp:将图片四周的像素扩展到周围区域
repeat:简单的水平竖直方向上的复制效果
mirror:水平竖直方向上的镜像效果
上面代码的执行效果图如下:
5、NinePatchDrawable
NinePatchDrawable 对应的XML顶层标签是 <nine-patch> ,其用法和BitmapDrawable完全一样,只是加载的是一张.9图片。这里不再介绍NinePatchDrawable的具体用法,只介绍一下在Android Studio中如何制作.9图片。具体步骤如下:
Android Studio中制作.9图片的方式: 1、选择一张图片,右键点击“Create 9-Patch File”,即可生成一张.9图片 2、生成的.9图片和原始图片在同一个文件夹中,可以根据需要挪动图片位置 3、在.9图片的四条边上选取像素,选取的像素是在缩放过程中会变形的像素,其他像素都是不会变形的像素
6、LayerDrawable
LayerDrawable 对应的XML顶层标签是 <layer-list> ,它表示一种层次化的Drawable集合,即它可以将多个Drawable叠加起来使用,达到最终的效果。下面是一个使用LayerDrawable的示例代码:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <solid android:color="@android:color/darker_gray" /> </shape> </item> <item android:bottom="10.0dip"> <shape> <solid android:color="@android:color/white" /> </shape> </item> <item android:bottom="1.0dip" android:left="1.0dip" android:right="1.0dip"> <shape> <solid android:color="@android:color/white" /> </shape> </item> </layer-list>
上面代码的运行效果图如下图所示,可以看到是一个类似输入框的效果:
从上面的例子可以看出:<item>标签中可以直接使用 android:drawable 或 android:id 属性指定资源id;也可以在标签内部添加一些其他的Drawable类型,如<shape>等;<item>标签中可以使用 android:top、android:bottom、android:left、android:right属性指定间距。
7、InsetDrawable
InsetDrawable 对应的XML顶层标签是 <inset> 。当一个View希望自己的背景比自己的实际区域小的时候,就可以使用InsetDrawable来实现。例如,我想让我的ImageView中的图片大小距离ImageView边界10dp,我就可以编写如下代码来实现:
<?xml version="1.0" encoding="utf-8"?> <inset xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@mipmap/image01" android:insetBottom="10.0dip" android:insetLeft="10.0dip" android:insetRight="10.0dip" android:insetTop="10.0dip" />
可以看到,InsetDrawable通过设置android:insetTop、android:insetBottom、android:insetLeft、android:insetRight来指定四个边的内凹大小。
当然,这种需求也可以使用LayerDrawable来实现。
8、TransitionDrawable
TransitionDrawable 对应的XML顶层标签是 <transition> ,它可以让一个View的背景从图片A渐变到图片B。这里的渐变的意思是:图片A逐渐消失,同时图片B逐渐显现。我们可以编写如下代码来实现这个效果:
<?xml version="1.0" encoding="utf-8"?> <transition xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/image01" /> <item android:drawable="@mipmap/image02" /> </transition>
一个<transition>标签中只能有两个<item>子标签,也就是说,TransitionDrawable最多只支持两张图片之间进行渐变。但是,只在XML文件中写这些代码是不够的,我们还需要在JAVA代码中设置开始渐变。具体代码如下:
ImageView img = (ImageView) findViewById(R.id.drawable_main_iv_img); TransitionDrawable drawable = (TransitionDrawable) img.getDrawable(); drawable.startTransition(60000);
9、AnimationDrawable
AnimationDrawable 对应的XML顶层标签是 <animation-list> ,表示的是一个帧动画Drawable。下面是一个使用AnimationDrawable的示例代码:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" android:visible="true"> <item android:drawable="@mipmap/image01" android:duration="1000" /> <item android:drawable="@mipmap/image02" android:duration="1000" /> <item android:drawable="@mipmap/ic_launcher" android:duration="1000" /> <item android:drawable="@mipmap/ic_launcher_round" android:duration="1000" /> </animation-list>
在上面的代码中,我们使用 android:oneshot 属性设置帧动画是否只进行一次,如果为false,则可以永久进行。我们可以设置<item>子标签,设置每一帧显示的图片和显示时长。最后,我们还需要在JAVA代码中调用AnimationDrawable的 start() 方法,开始播放帧动画。代码如下:
AnimationDrawable drawable = (AnimationDrawable) img.getDrawable();
drawable.start();
10、LevelListDrawable
LevelListDrawable 对应的XML顶层标签是 <level-list> ,它表示一个Drawable集合,集合中的每个Drawable都有一个等级(Level)的概念,LevelListDrawable可以根据不同等级选择显示集合中的不同Drawable。下面是一个使用LevelListDrawable的示例代码:
<?xml version="1.0" encoding="utf-8"?> <level-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/image01" android:maxLevel="5" /> <item android:drawable="@mipmap/image02" android:maxLevel="50" /> <item android:drawable="@mipmap/ic_launcher" android:maxLevel="500" /> <item android:drawable="@mipmap/ic_launcher_round" android:maxLevel="5000" /> </level-list>
我们在LevelListDrawable的集合中放了四个Drawable,分别使用 android:maxLevel 设置Drawable的Level,然后在JAVA代码中,当我们点击图片的时候,就会随机选择一张图片。JAVA代码如下:
int[] levels = {5, 50, 500, 5000}; ImageView img = (ImageView) findViewById(R.id.drawable_main_iv_img); img.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int index = (int) (Math.random() * 4); img.setImageLevel(levels[index]); } });
通过调用ImageView的 setImageLevel() 方法来设置图片的Level。除了这种方法之外,我们还可以直接调用Drawable对象的 setLevel() 方法设置Level。这样,我们就可以在每次点击图片的时候随机生成一个下标,从数组中取出对应的Level设置给LevelListDrawable。
还需要注意一点,这里的Level最好介于 0 和 10000 之间。
11、RotateDrawable
RotateDrawable 对应的XML顶层标签是 <rotate> ,用来制作一个可以旋转的Drawable。下面是使用RotateDrawable的一个示例代码:
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@mipmap/image02" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="360" android:visible="true" />
RotateDrawable中各个属性的详细解释如下:
android:drawable:Drawable中显示的图片
android:fromDegrees:旋转开始时的角度
android:toDegrees:旋转结束时的角度
android:pivotX:选中中心点X坐标在宽度上的百分比
android:pivotY:选中中心点Y坐标在高度上的百分比
使用RotateDrawable时,我们也需要在JAVA代码中设置Drawable的Level(0<=Level<=10000,默认为0),来控制旋转的百分比。例如,在上面的代码中,我设置了这个Drawable从0°旋转到360°,那么当这个Drawable旋转角度为0°时,其Level是0,当旋转到360°时,Level是10000。因此,如果我在JAVA代码中设置Level为1000,那么这个Drawable就会旋转10%,即36°。
现在我想在JAVA代码中控制这个Drawable翻转,即旋转180°,JAVA代码如下:
ImageView img = (ImageView) findViewById(R.id.drawable_main_iv_img); RotateDrawable drawable = (RotateDrawable) img.getDrawable(); drawable.setLevel(5000);
11、ScaleDrawable
ScaleDrawable 对应的XML顶层标签是 <scale> ,用来控制Drawable的缩放。下面是一个使用ScaleDrawable的示例代码:
<?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@mipmap/image01" android:scaleGravity="center" android:scaleHeight="70%" android:scaleWidth="70%" />
ScaleDrawable中各个属性的详细解释如下:
android:drawable:Drawable中显示的图片
android:scaleWidth:Drawable缩放的宽度的百分比
android:scaleHeight:Drawable缩放的高度的百分比
android:scaleGravity:Drawable缩放后显示的位置,有以下值:
top:将图片放在容器顶部,不改变其大小
bottom:将图片放在容器底部,不改变其大小
left:将图片放在容器左部,不改变其大小(默认值)
right:将图片放在容器右部,不改变其大小
center:将图片放其容器的中心,不改变其大小
center_horizontal:将图片放在容器水平中间,不改变其大小
center_vertical:将图片放在容器垂直中间,不改变其大小
fill:将图片填充容器的宽和高
fill_horizontal:将图片水平填充容器的宽,图片的高不变
fill_vertical:将图片垂直填充容器的高,图片的宽不变
ScaleDrawable也需要在JAVA代码中设置Level(0<=Level<=10000,默认为0),这里的Level一定不能为0,且Level会与scaleWidth、scaleHeight属性一起控制Drawable的缩放。缩放后Drawable显示的实际大小的计算方法如下:
w -= (int) (w * (10000 - level) * mState.mScaleWidth / 10000);
h -= (int) (h * (10000 - level) * mState.mScaleHeight / 10000);
因此,我们在实际使用中,Level一般设置为1即可。JAVA代码如下:
ImageView img = (ImageView) findViewById(R.id.drawable_main_iv_img); ScaleDrawable drawable = (ScaleDrawable) img.getDrawable(); drawable.setLevel(1);
12、ClipDrawable
ClipDrawable 对应的XML顶层标签是 <clip> ,它可以用来裁剪一张图片。下面是一个使用ClipDrawable的示例代码:
<?xml version="1.0" encoding="utf-8"?> <clip xmlns:android="http://schemas.android.com/apk/res/android" android:clipOrientation="horizontal" android:drawable="@mipmap/image02" android:gravity="center" />
ClipDrawable中各个属性的详细解释如下:
android:drawable:Drawable中显示的图片
android:clipOrientation:Drawable的裁剪方向
android:gravity:Drawable裁剪后的显示方式(Drawable的裁剪方式),可以有以下值:
top:将图片放在容器顶部,其大小不变;如果为垂直裁剪,则从底部开始裁剪
bottom:将图片放在容器底部,其大小不变;如果为垂直裁剪,则从顶部开始裁剪
left:将图片放在容器左侧,其大小不变;如果为水平裁剪,则从右侧开始裁剪
right:将图片放在容器右侧,其大小不变;如果为水平裁剪,则从左侧开始裁剪
center:将图片放在容器中央,其大小不变;如果为水平裁剪,则从左右两侧同时开始裁剪;如果为垂直裁剪,则从上下两侧同时开始裁剪
center_horizontal:将图片在水平方向居中显示,其大小不变;如果为水平裁剪,则从左右两侧同时裁剪
center_vertical:将图片在垂直方向居中显示,其大小不变;如果为垂直裁剪,则从上下两侧同时裁剪
fill:将图片填充容器,仅当Level为0时才会裁剪,此处裁剪为全部裁剪掉
fill_horizontal:将图片水平方向填充容器,垂直方向不变,仅当Level为0时才会裁剪,此处裁剪为全部裁剪掉
fill_vertical:将图片垂直方向填充容器,水平方向不变,仅当Level为0时才会裁剪,此处裁剪为全部裁剪掉
ClipDrawable也需要在JAVA代码中设置Level(0<=Level<=10000,默认为0),这里的Level决定的是裁剪的百分比。当Level为0时,表示全部裁剪,当Level为10000时,表示不裁剪。裁掉的区域所占原图的百分比的计算公式为: (10000 - Level) / 10000 。
使用ClipDrawable,需要注意以下两点:
(1)当clipOrientation和gravity两个属性发生冲突的时候,以clipOrientation属性为准,且gravity属性值自动变为center;
(2)如果gravity属性设置成左右/上下同时裁剪,那么左右/上下分别裁剪总裁剪区域的一半。如:我的Level设置为2000,且gravity属性值为center_vertical,那么上下两侧各被裁剪10%。
Drawable的其他用法
1、获取Drawable的两种方式
(1)当Drawable作为View的背景时:Drawable drawable = view.getBackground();
(2)当Drawable作为ImageView的资源时:Drawable drawable = view.getDrawable();
2、获取Drawable宽高的两种方式(以宽为例)
(1)int width = drawable.getBounds().width();
(2)int width = drawable.getIntrinsicWidth();
posted on 2017-06-08 14:51 ITGungnir 阅读(1096) 评论(0) 编辑 收藏 举报