第七章实现炫酷效果—图像和动画
学完上一章,相信读者对Android画图核心部分有了一定的了解。为了实现更加炫酷的效果,我们可能会在我们的应用中使用大量的图像和动画效果。
本章我们将详细介绍Android中的各种图像对象的使用,以及动画的使用。学习完本章,相信读者可以独立开发出有着绚丽的视觉效果的Android应用了。
7.1 Android的几种常用图像类型
Android中的图像对象,主要有android.graphics.Bitmap(位图)、android.graphics.drawable.Drawable(基于Drawable类扩展出各种绘图的类)和android.graphics.drawable.Picture。
下面简单介绍一下这几种图像类型,以便对之有个大概的了解。。
1)Bitmap
称作位图,一般位图的文件格式后缀为bmp,当然编码器也有很多,如RGB565、RGB8888等等。作为一种逐像素的显示对象执行效率高,但是缺点也很明显,那就是存储效率低。我们将Bitmap理解成为一种存储对象比较好。
2)Drawable
作为Android中通用的图形对象,它可以装载常用格式的图像,比如GIF、PNG、JPG,当然也支持BMP,当然它还提供一些高级的可视化对象,比如渐变、图形等。
3)Picture
相对于Drawable和Bitmap而言,Picture对象就小巧的多,它并不存储实际的像素,仅仅记录了绘制的过程。
下面会对几种图像类型做详细的讲解。
7.2图片的基础—Bitmap(位图)
7.2.1如何获取位图资源
前面我们大概了解了几种图像类的功能,这其中,Bitmap类是一个使用率较高的类。下面详细说明下Bitmap这个类。
先来看看如何获取位图资源。Bitmap对象没有公有的构造方法,所以不能直接创建,只能通过BitmapFactory的几个静态方法创建。
一般的,获取位图资源有以下几种方式:
1)图片放在sd卡中
Bitmap imageBitmap = BitmapFactory.decodeFile(path); |
这里path是图片的路径,根目录是/sdcard。
2)图片在项目的res文件夹下面
ApplicationInfo appInfo = getApplicationInfo(); int resID = getResources().getIdentifier(name, "drawablePath", appInfo.packageName); Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), resID); |
这里是通过图片的id,或直接通过R文件来获取(例如R.drawable.bitmapName)图片的。
这里的name,是该图片的名字;drawablePath是该图片存放的目录,appInfo.packageName是应用程序的包。
3)图片放在src目录下
// 图片存放的路径 String path = "com/xiangmu/test.png"; // 得到图片流 InputStream is = getClassLoader().getResourceAsStream(path); Bitmap mBitmap = BitmapFactory.decodeStream(is); |
4)android中有个Assets目录,这里可以存放只读文件
// 图片存放的路径为assets/test.png String path = "test.png"; InputStream is = getResources().getAssets().open(path); Bitmap mBitmap = BitmapFactory.decodeStream(is); |
经验分享: 一些低版本的Android系统(2.2版本以前)对res/raw和assets文件夹资源大小有限制的,原始文件大小超过1M,将不能从APK中读出。如果你使用AssetManager 或 Resources类的方法来获取InputStream,将抛出java.io.IOException的异常。这一点是特别需要注意的。 所以,为了兼容低版本的Android系统,如果需要放入大于1M的原始文件,可以事先将大文件分割成小文件,然后在程序启动时将文件合并,拷贝到SD卡中,以供程序读取。 |
7.2.2如果获取位图的信息
很多场合,我们需要获取位图信息,比如位图大小、是否包含透明度、颜色格式等。Bitmap类中支持很多方法,下面简单介绍一些常用的方法,如表7-1所示。
方法 |
返回值 |
说明 |
getWidth() |
int |
获取位图的宽 |
getHeight() |
int |
获取位图的高 |
hasAlpha() |
boolean |
是否包含透明度 |
getConfig() |
Config |
获取颜色格式 |
表7-1 Bitmap类中常用的一些方法
经验分享: 通过方法getConfig()得到的是这个位图的颜色格式(android.graphics.Bitmap.Config),了解这个类对Android开发过程还是挺有用的。这是Bitmap的一个内部类。 public enum Config { ALPHA_8 (2),//表示图形单个像素点由一个字节(8位)来表示,代表8位Alpha位图。 RGB_565 (4),// 5+6+5=16,表示图形单个像素点由两个字节来表示的16位RGB位图。 ARGB_4444 (5),// 4+4+4+4=16,表示图形单个像素点由两个字节来表示的16位ARGB位图。 ARGB_8888 (6);// 8+8+8+8=32,表示图形单个像素点由四个字节来表示的32位ARGB位图。 } ALPHA_8,ARGB_4444,ARGB_8888都是透明的位图。也就是说字母A代表透明。位图位数越高代表其可以存储的颜色信息越多,当然图像也就越逼真。 |
7.2.3位图的显示与变换
有了位图,我们就要将它显示出来。显示需要使用核心类Canvas,可以直接通过Canvas类的drawBitmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas。具体的可以参考前面Canvas相关的章节。
位图的变换,还是要用到前面提到的类android.graphics.Matrix。变换可以在画的时候,也可以在加载图片的时候对,原图片进行变换。
在Canvas画的时候进行变换的方法如下:
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint); // 指定Matrix绘制位图 drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) |
这里主要介绍下在原有位图的基础上,缩放原位图,创建一个新的位图。下面是android.graphics.Bitmap自带的一个方法。
Bitmap.createBitmap (Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) |
还有一种创建新位图的方法是通过BitmapFactory.decodeFile()方法。在操作Android图片的时候,我们会经常遇到内存溢出的问题,比如加载8M以上的图片的时候,很容易造成内存溢出,因为android规定一个应用可以使用的内存为8M左右,如何优化我们会在后面单独的一章节来介绍。下面我们来看看如何将一个大图变小,来给我们使用:
BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; // 这里是整个方法的关键,inJustDecodeBounds设为true时将不为图片分配内存。 BitmapFactory.decodeFile("/sdcard/image.jpg",opts); // 获取图片的原始宽度 int srcWidth = opts.outWidth; // 获取图片原始高度 int srcHeight = opts.outHeight; int destWidth = 0; int destHeight = 0; // 缩放的比例 double ratio = 0.0; // 按比例计算缩放后的图片大小,maxLength是长或宽允许的最大长度 if(srcWidth >srcHeight) { ratio = srcWidth / maxLength; destWidth = maxLength; destHeight = (int) (srcHeight / ratio); }else { ratio = srcHeight / maxLength; destHeight = maxLength; destWidth = (int) (srcWidth / ratio); } BitmapFactory.Options newOpts = new BitmapFactory.Options(); // 缩放的比例,缩放是很难按准备的比例进行缩放的,目前我只发现只能通过inSampleSize来进行缩放,其值表明缩放的倍数,SDK中建议其值是2的指数值 newOpts.inSampleSize = (int) ratio + 1; // inJustDecodeBounds设为false表示把图片读进内存中 newOpts.inJustDecodeBounds = false; // 设置大小,这个一般是不准确的,是以inSampleSize的为准,但是如果不设置却不能缩放 newOpts.outHeight = destHeight; newOpts.outWidth = destWidth; // 获取缩放后图片 Bitmap destBm = BitmapFactory.decodeFile("/sdcard/ image.jpg",newOpts); |
经验分享: 对于BitmapFactory.Options. inJustDecodeBounds说明一下。 如果该值设为true,使用BitmapFactory.decodeFile()方法将不返回实际的bitmap同时不会给其分配内存空间而返回的Options里面只包括一些解码边界信息即图片大小信息。 那么相应的方法也就出来了,通过设置inJustDecodeBounds为true,获取到outHeight(图片原始高度)和outWidth(图片的原始宽度),然后计算一个inSampleSize(缩放值),然后就可以读取图片了,这里要注意的是Options.inSampleSize 不可以小于0。也就是说先将Options的属性inJustDecodeBounds设为true,先获取图片的基本大小信息数据(信息没有保存在bitmap里面,而是保存在options里面),通过options.outHeight和options. outWidth获取的大小信息以及自己想要到得图片大小计算出来缩放比例inSampleSize,然后紧接着将inJustDecodeBounds设为false,就可以根据已经得到的缩放比例得到缩放后的图了。设置新的Options,一定要设置outHeight和outWidth如果不设置将不能缩放。 |