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代码:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
< color xmlns:android = "http://schemas.android.com/apk/res/android" |
3 |
android:color = "#FF0000" /> |
当然也可以使用Java代码创建ColorDrawable,需要注意的是Android中使用一个int类型的数据表示颜色值,通常习惯使用十六进制格式的数据表示颜色值。一个int类型包含四个字节,分别代表颜色的4个组成部分:透明度(Alpha)、红(RED)、绿(GREEN)、蓝(BLUE),每个部分由一个字节(8个bit)表示,取值范围为0~255。在xml中使用颜色时可以省略透明度(Alpha)部分,如#ff0000表示红色。但是在代码中必须要明确指出透明度(Alpha)代表的数据,如果省略了就表示完全透明的颜色,例如0xFFFF0000表示红色,而0xFF0000虽然也表示红色,但它却是完全透明的,也就是说当绘制到画布上时,看不出有任何效果。
使用Java代码也可以创建ColorDrawable,代码如下:
[代码]java代码:
1 |
ColorDrawable
drawable = new ColorDrawable( 0xffff0000 ); |
二、GradientDrawable
GradientDrawable 表示一个渐变区域,可以实现线性渐变、发散渐变和平铺渐变效果,在Android中可以使用GradientDrawable表示很多复杂而又绚丽的界面效果。
可以使用xml定义GradientDrawable,相对于ColorDrawable类型,GradientDrawable要复杂很多,它有很多的元素组成。在xml文件中使用shape作为根节点来创建GradientDrawable,它包含很多属性和子节点,下面是GradientDrawable的xml文档节点结构。
[代码]xml代码:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
< shape xmlns:android = "http://schemas.android.com/apk/res/android" > |
4 |
< gradient >//设置区域背景的渐变效果 |
5 |
< solid />//设置区域的背景颜色,如果设置了solid会覆盖gradient的效果 |
其中每个节点都有许多属性需要设置,以达到不同的渐变效果。
以下是几种不同渐变效果实现的xml文件代码:
[代码]xml代码:
02 |
<? xml version = "1.0" encoding = "utf-8" ?> |
04 |
xmlns:android = "http://schemas.android.com/apk/res/android" |
08 |
android:startColor = "#ff0000" |
09 |
android:centerColor = "#00ff00" |
10 |
android:endColor = "#0000ff" |
15 |
android:dashWidth = "4dip" |
16 |
android:dashGap = "5dip" /> |
20 |
<? xml version = "1.0" encoding = "utf-8" ?> |
21 |
< shape xmlns:android = "http://schemas.android.com/apk/res/android" |
22 |
android:shape = "ring" android:innerRadiusRatio = "8" |
23 |
android:thicknessRatio = "3" android:useLevel = "false" > |
24 |
< gradient android:type = "sweep" android:useLevel = "false" |
25 |
android:startColor = "#ff0000" android:endColor = "#0000ff" android:centerColor = "#00ff00" /> |
29 |
<? xml version = "1.0" encoding = "utf-8" ?> |
30 |
< shape xmlns:android = "http://schemas.android.com/apk/res/android" |
31 |
android:shape = "ring" android:innerRadius = "0dip" |
32 |
android:thickness = "70dip" android:useLevel = "false" > |
33 |
< gradient android:type = "radial" android:useLevel = "false" android:gradientRadius = "70" |
34 |
android:startColor = "#ff0000" android:endColor = "#0000ff" android:centerColor = "#00ff00" /> |
以下几幅图展示了上述三个渐变效果:
图6-1 线性渐变效果的椭圆
图6-2 平铺渐变效果的圆环
图6-3 发散渐变效果的圆
三、BitmapDrawable
BitmapDrawable 是对bitmap的一种包装,可以设置它包装的bitmap在BitmapDrawable区域内的绘制方式,如平铺填充、拉伸填充或者保持图片原始大小,也可以在BitmapDrawable区域内部使用gravity指定的对齐方式。
在xml文件中使用bitmap作为根节点来定义BitmapDrawable。
下面的xml代码定义一个BitmapDrawable,同时设置了BitmapDrawable的tileMode 属性为mirror,通过这样设置会使用小图片在水平和竖直方向做镜面平铺效果。
[代码]xml代码:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
< bitmap xmlns:android = "http://schemas.android.com/apk/res/android" |
3 |
android:src = "@drawable/png_icon_416" |
4 |
android:tileMode = "mirror" |
5 |
android:antialias = "true" |
也可以使用Java代码实现相同的效果,等价的Java代码如下:
[代码]java代码:
1 |
Bitmap
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.png_icon_416); |
2 |
BitmapDrawable
mBitmapDrawable = new BitmapDrawable(mBitmap); |
3 |
mBitmapDrawable.setTileModeXY(TileMode.MIRROR,
TileMode.MIRROR); |
4 |
mBitmapDrawable.setAntiAlias( true ); |
5 |
mBitmapDrawable.setDither( true ); |
6 |
mDrawable
= mBitmapDrawable; |
效果如下图所示:
图6-4 BitmapDrawable运行效果图
四、NinePatchDrawable
NinePatchDrawable,“点九图”是Andriod平台的一种特殊的图片格式,文件扩展名为:.9.png。支持Android平台的手机类型很多,有多种不同的分辨率,很多控件的切图文件在被放大拉伸后,边角会模糊失真。在android平台下使用“点九”图片处理技术,可以将图片横向和纵向同时进行拉伸,以实现在多分辨率下的完美显示效果。点九图片在拉伸时仍能保留图像的渐变质感和圆角的精细度。
Android SDK工具集提供了处理点九图片的工具,可以通过draw9patch.bat运行,通过这个工具可以很容易把普通的PNG图片处理成“点九”图片。从它的名字也很容易理解“点九”图的含义,其实相当于把一张PNG图分成了9个部分(九宫格),分别为4个角,4条边,以及一个中间区域,4个角是不做拉伸的,所以还能一直保持圆角的清晰状态,而2条水平边和2条垂直边分别只做水平和垂直拉伸,所以不会出现边框被拉粗的情况,只有中间用黑线指定的区域做拉伸,通过这种处理方式图片才不会失真。如图6-5所示,对4条黑线分别做了注释。左边和上边的黑线形成的矩形区域是图片的拉伸区域,下边和右边形成的矩形区域是内容所在的区域。黑线可以是连续的也可以是不连续的,不过为了达到最好的显示效果,最好使用连续的黑线。
图6-5 点九图片示意图
使用了*.9.png图片技术后,只需要采用一套界面切图去适配不同的分辨率,而且大幅减少安装包的大小。Android FrameWork在显示点九图片时使用了高效的优化算法,所示应用程序不需要专门做处理就可以实现图片拉伸自适应,减少了代码量和实际开发的工作量。
在xml文件中使用使用nine-patch作为根节点创建NinePatchDrawable。同时,也可以使用bitmap包装点九图片,android FrameWork会根据android:src属性设置的图片类型来生成对应的drawable。代码如下:
[代码]xml代码:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
3 |
xmlns:android = "http://schemas.android.com/apk/res/android" |
4 |
android:src = "@drawable/droid_logo" |
5 |
android:dither = "true" /> |
[代码]xml代码:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
3 |
xmlns:android = "http://schemas.android.com/apk/res/android" |
4 |
android:src = "@drawable/droid_logo" |
5 |
android:dither = "true" /> |
下面看一下原始点九图片以及拉伸之后的效果:
图6-6 原始点九图片
图6-7 点九图片拉伸之后的效果
最后,需要指出的是,Android虽然可以使用Java代码创建NinePatchDrawable,但是极少情况会那么做,主要的原因是由于Android SDK会在编译工程时对点九图片进行编译,形成特殊格式的图片。使用代码创建NinePatchDrawable时只能针对编译过的点九图片资源,对于没有编译过的点九图片资源都当做BitmapDrawable对待。在使用点九图片时需要注意的是,点九图只能适用于拉伸的情况,对于压缩的情况并不适用,如果需要适配很多分辨率的屏幕时需要把点九图做的小一点。
五、InsetDrawable
InsetDrawable 表示一个drawable嵌入到另外一个drawable内部,并且在内部留一些间距,这一点很像drawable的padding属性,区别在于 padding表示drawable的内容与drawable本身的边距,insetDrawable表示两个drawable和容器之间的边距。当控件需要的背景比实际的边框小的时候比较适合使用InsetDrawable。
在xml文件中使用inset作为跟节点定义InsetDrawable。
下面的xml定义了一个四边边距都为20dip的InsetDrawable,代码如下:
[代码]xml代码:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
< inset xmlns:android = "http://schemas.android.com/apk/res/android" |
3 |
android:drawable = "@drawable/bitmap_bell" |
4 |
android:insetLeft = "20dp" |
5 |
android:insetRight = "20dp" |
6 |
android:insetTop = "20dp" |
7 |
android:insetBottom = "20dp" |
效果如下图所示:
图6-8 InsetDrawable运行效果图
六、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)方法来设置剪切区域。
下面为定义ClipDrawable的代码:
[代码]xml代码:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
< clip xmlns:android = "http://schemas.android.com/apk/res/android" |
3 |
android:clipOrientation = "horizontal" |
4 |
android:drawable = "@drawable/bitmap_android" |
如果没有android:drawable属性,必须要设置一个任意类型的drawable作为子节点,代码如下:
[代码]xml代码:
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< clip xmlns:android = "http://schemas.android.com/apk/res/android" |
03 |
android:clipOrientation = "horizontal" |
04 |
android:gravity = "left" |
07 |
android:src = "@drawable/android_text" |
08 |
android:gravity = "center" |
效果如下图所示:
图6-9 ClipDrawable运行效果图
】七、ScaleDrawable
ScaleDrawable是对一个Drawable进行缩放操作,可以根据level属性控制这个drawable的缩放比率,也可以设置它在容器中的对齐方式。
在xml文件中使用scale作为根节点来创建RotateDrawable。
创建ScaleDrawable的代码如下:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
<!--
android:scaleGravity=""可以设置缩放的对齐方式 --> |
4 |
android:drawable = "@drawable/smiley_smile" |
5 |
android:scaleWidth = "100%" |
6 |
android:scaleHeight = "100%" |
效果如下图所示:
图6-10 ScaleDrawable运行效果图
八、 RotateDrawable
RotateDrawable 是对一个Drawable进行旋转操作,可以根据level属性控制这个drawable旋转角度,也可以设置相对于它所在容器的对齐方式。
在xml文件中使用rotate作为根节点来定义RotateDrawable.
创建RotateDrawable的代码如下:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
3 |
android:drawable = "@drawable/smiley_smile" |
效果如下图所示:
图6-11 RotateDrawable运行效果图
九、AnimationDrawable
AnimationDrawable 对应于Android中的帧动画,就是把一系列的drawable按照一定的顺序,一帧一帧的播放,并且可以使用android:oneshot属性设置是否循环播放。
在xml文件中使用animation-list作为根节点定义AnimationDrawable,使用item设置需要播放的每一帧使用的drawable资源,以及每一帧持续的时常。
下面的代码定义了一个包含五帧的AnimationDrawable,帧间隔为300毫秒,代码如下:
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
03 |
android:oneshot = "false" > |
05 |
android:drawable = "@drawable/level1" |
06 |
android:duration = "300" |
09 |
android:drawable = "@drawable/level2" |
10 |
android:duration = "300" |
13 |
android:drawable = "@drawable/level3" |
14 |
android:duration = "300" |
17 |
android:drawable = "@drawable/level4" |
18 |
android:duration = "300" |
21 |
android:drawable = "@drawable/level5" |
22 |
android:duration = "300" |
定义了AnimationDrawable之后需要主动调用AnimationDrawable的start播放动画,需要注意的是,当我们在Activity的oncreate方法中调用start方法时会没有任何效果,那是因
为view还没有初始化完成,无法播放动画,所以需要使用handler来延迟播放动画,具体实现代码如下:
1 |
mHandler.postDelayed( new Runnable()
{ |
5 |
//
TODO Auto-generated method stub |
6 |
((AnimationDrawable)mDrawable).start(); |
十、LayerDrawable
LayerDrawable 管理一组drawable,每个drawable都处于不同的层,当它们被绘制的时候,按照顺序全部都绘制到画布上。虽然这些drawable会有交差或者重叠的区域,但是它们是位于不同的层,彼此之间不会影响。
在xml文件中使用layer-list作为根节点来定义LayerDrawable,通过item子节点定义每一层的drawable,layer-list没有属性节点,只包含item子节点。
下面的xml定义了一个包含三层的LayerDrawable,为了清楚的看到它们分别位于不同的层,可以给每一层都设置了一些透明度,代码如下:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
3 |
< item android:drawable = "@drawable/layer1" /> |
4 |
< item android:drawable = "@drawable/layer2" /> |
5 |
< item android:drawable = "@drawable/layer3" /> |
效果如下图所示:
图6-12 LayerDrawable运行效果图
十一、LevelListDrawable
管理一组drawable,每一个drawable都对应一个level范围,当它们被绘制的时候,根据level属性值选取对应的一个drawable绘制到画布上。
在xml文件中使用level-list作为根节点来定义LevelListDrawable,通过item子节点定义每一层的drawable,level-list没有属性节点,只包含item子节点。
创建LevelListDrawable的代码如下:
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
05 |
android:maxLevel = "2000" |
06 |
android:drawable = "@drawable/level1" />
|
08 |
android:maxLevel = "4000" |
09 |
android:drawable = "@drawable/level2" /> |
11 |
android:maxLevel = "6000" |
12 |
android:drawable = "@drawable/level3" /> |
14 |
android:maxLevel = "8000" |
15 |
android:drawable = "@drawable/level4" /> |
17 |
android:maxLevel = "10000" |
18 |
android:drawable = "@drawable/level5" /> |
效果如下图所示:
图6-13 LevelListDrawable运行效果图1
图6-14 LevelListDrawable运行效果图2
十二、StateListDrawable
StateListDrawable管理一组drawable,每一个drawable都对应着一组状态,状态的选择类似于java中的switch-case组合,按照顺序比较状态,当遇到匹配的状态后,就返回对应的drawable,因此需要把最精确的匹配放置在最前面,按照从精确到粗略的顺序排列。
StateListDrawable在Android中使用的非常广泛,所有控件的背景基本上都使用了StateListDrawable,比如按钮就具有很多状态,按下状态、选中状态、默认状态、禁用状态等等,像这样在不用的状态下显示效果不一样的时候,就是需要使用StateListDrawable的时候。
在xml文件中使用selector作为根节点来定义StateListDrawable,并使用item定义不同状态下的drawable。
创建StateListDraw的代码如下:
01 |
<? xml version = "1.0" encoding = "utf-8" ?> |
03 |
< item android:state_focused = "false" |
04 |
android:state_pressed = "false" |
05 |
android:drawable = "@drawable/gradient_normal" |
08 |
< item android:state_pressed = "true" |
09 |
android:drawable = "@drawable/gradient_pressed" |
12 |
< item android:state_focused = "true" |
13 |
android:drawable = "@drawable/gradient_focused" |
效果如下图所示:
图6-15 Normal状态下StateListDrawable运行效果图
图6-16 Focused状态下StateListDrawable运行效果图
图6-17 Pressed状态下StateListDrawable运行效果图
十三、TransitionDrawable
TransitionDrawable 是LayerDrawable的子类,不过它只负责管理两层drawable,并且提供了一个透明度变化的动画,可以控制从一层drawable过度到另外一层drawable的动画效果。
在xml文件中使用transition作为根节点来定义TransitionDrawable,通过item子节点定义两层使用的drawable。
创建TransitionDrawable的代码如下:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
3 |
< item android:drawable = "@drawable/smiley_smile" /> |
4 |
< item android:drawable = "@drawable/smiley_smile_glasses" /> |
在使用AnimationDrawable的时,需要主动调用startTransition方法启动两个层之间的切换动画,也可以调用reverseTransition方法启动逆向切换动画,它们都可以接受一个毫秒
数,作为动画的持续时间。代码如下:
1 |
mHandler.postDelayed( new Runnable()
{ |
5 |
//
TODO Auto-generated method stub |
6 |
((TransitionDrawable)mDrawable).startTransition( 2000 ); |
效果如下图所示:
图6-18 TransitionDrawable运行效果图1
- Android中各种Drawable总结
在Android中,Drawable使用广泛,但是种类也多,基于<Android开发艺术探索>中对Drawable的讲解,总结了如下表格.
- android studio 目录结构讲解
android studio 目录结构讲解 src 毫无疑问,src目录是放置我们所有 Java代码的地方,它在这里的含义和普通 Java 项目下的 src目录是完全一样的,展开之后你将看到我们刚才创 ...
- Android指纹识别API讲解,让你有更好的用户体验
我发现了一个比较怪的现象.在iPhone上使用十分普遍的指纹认证功能,在Android手机上却鲜有APP使用,我简单观察了一下,发现Android手机上基本上只有支付宝.微信和极少APP支持指纹认证功 ...
- Android中Bitmap, Drawable, Byte,ID之间的转化
Android中Bitmap, Drawable, Byte,ID之间的转化 1. Bitmap 转化为 byte ByteArrayOutputStream out = new ByteArray ...
- Android中的Drawable和动画
Android中Drawable是一种可以在Canvas上进行绘制抽象的概念,种类很多,常见的颜色和图片都可以是一个Drawable.Drawable有很多种,它们表示一种图像的概念,但是它们又不全是 ...
- Android进阶(二十三)Android开发过程之实例讲解
Android开发过程之实例讲解 前言 回过头来审视之前做过的Android项目,发觉自己重新开发时忽然间不知所措了,间隔了太长时间没有开发导致自己的Android技能知识急剧下降.温故而知新. 废话 ...
- ssh 配置文件讲解大全 ssh调试模式 sftp scp strace进行调试 特权分离
ssh 配置文件讲解大全 ssh调试模式 sftp scp strace进行调试 特权分离 http://blog.chinaunix.net/uid-16728139-id-3265394.h ...
- GitHub上最著名的Android播放器开源项目大全
GitHub上最著名的Android播放器开源项目大全 ...
- Android下的Drawable使用
Drawable表示一种可绘制的内容,可以由图片或者颜色组成.Android下的Drawable有BitmapDrawable.GradientDrawable.LayerDrawable等等 1.B ...
随机推荐
- 初学JAVA的 感想 尹鑫磊
开始学习任何一门课(包括java),兴趣最重要.一直觉得自己在学计算机编程语言,学习了很多,但每门语言都停留在知识边缘地带,都没深入到它们的精华部分,对它们的精华部分知之甚少,于是趁学校开设这门课,并 ...
- cshtml常用标签
@RenderSection:在布局页中,将呈现指定部分的内容并指定该部分是否为必需.用法:@RenderSection("PageSpecificStyleSheetIncludes&qu ...
- final评价Ⅱ
1.飞天小女警: 礼物挑选这个项目相比之前的发布功能更完善了些,但是整体界面还是不太美观,用户界面上呈现出的选项字不够清晰,使用起来不是很方便,但是增加了猜你喜欢的功能,可以根据用户的浏览记录猜测用户 ...
- hdu1024 dp
题意:求一个序列中的最大 m 段和,m 段不能交叉. dp[i][0/1][j] 表示已经取完第 i 个物品,第 i 个物品取或不取,取到第 j 个子段. 用vis[i][0/1][j] 表示该 dp ...
- 简述 C、C++程序编译的内存分配情况【转】
面试题 9:简述 C.C++程序编译的内存分配情况 C.C++中内存分配方式可以分为三种: (1)从静态存储区域分配: 内存在程序编译时就已经分配好,这块内存在程序的整个运行期间都存在.速度快. ...
- error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
以前一直用的VC6.0,最近换成VS2010了.哎这几天光折腾VS2010了. 曾经我以为程序没啥头绪忒头疼,现在觉得乱七八糟的编译问题才叫一个头裂=口= 原因:VC6.0中,如果没有直接显示指定的返 ...
- Timberwolves forward Kevin Garnett to retire _洛杉矶时报
Timerwolves:森林狼队,forward:前锋; kevin Garnett,the best player in Minnesota Timberwolves history,is expe ...
- sql server 条件 not in (null)总是false
SELECT 1 WHERE 2 NOT IN ( 1 ); 结果: (无列名) 1 SELECT 1 WHERE 2 NOT IN ( 1, NULL ); 结果:(无列名) ...
- linux 删除进程的多种方法
kill pid kill -9 pid kill -15 pid pkill -f *.php kill -s 9 pid
- FCN网络的训练——以SIFT-Flow 数据集为例
参考文章: http://blog.csdn.net/u013059662/article/details/52770198 caffe的安装配置,以及fcn的使用在我前边的文章当中都已经提及到了,这 ...