基础知识
在介绍安卓中的动画效果之前,有必要介绍一下安卓中的图片处理机制。图片的特效包括图形的缩放、镜面、倒影、旋转、平移等。图片的特效处理方式是将原图的图形矩阵乘以一个特效矩阵,形成一个新的图形矩阵来实现的。矩阵matrix 类,维护了一个3*3 的矩阵去更改像素点的坐标。android 手机的屏幕坐标系以左上角为原点,从左向右为x轴正方向,从上到下为y轴正方向。第一行表示像素点的x 坐标:x = 1*x + 0*y + 0*z,第二行表示像素点的y 坐标:y = 0*x + 1*y + 0*z,第三行表示像素点的z 坐标:z = 0*x + 0*y + 1*z。图片的特效处理正是通过更改图形矩阵的值来实现的,在android下matrix这个类帮我们封装了矩阵的一些基本用法,所以我们可以直接使用即可。用代码编辑图片,最好处理都是图片在内存中的拷贝,不去处理原图,因此需要用bitmap创建一个与原图大小一致,格式相同的空白位图。
对照片进行操作的基本步骤:
1. 创建一个空白的bitmap,宽高信息和原图保存一致;
2. 创建一个画板;
3. 创建一个画笔;
4. 设置matrix矩阵;
5. 对照着原图在画纸上面画出一模一样的样子出来。
下面分别给出对图片缩放、平移、旋转、镜面操作的代码。
/** * 图片缩放 * */ private void zoom() { bitmap srcbitmap = bitmapfactory.decodefile(mnt/sdcard/b.jpg); iv_src.setimagebitmap(srcbitmap); bitmap copybitmap = bitmap.createbitmap(srcbitmap.getwidth(), srcbitmap.getheight(), srcbitmap.getconfig()); canvas canvas = new canvas(copybitmap); paint paint = new paint(); paint.setcolor(color.black); matrix matrix = new matrix(); matrix.setscale(0.6f, 0.6f); canvas.drawbitmap(srcbitmap, matrix, paint); iv_dest.setimagebitmap(copybitmap); } /** * 图片平移 * */ public void translation(){ options ops = new options(); ops.insamplesize = 4; //等比放缩 bitmap srcbitmap = bitmapfactory.decodefile(/mnt/sdcard/b.jpg,ops); iv_src.setimagebitmap(srcbitmap); bitmap copybitmap = bitmap.createbitmap(srcbitmap.getwidth(), srcbitmap.getheight(), srcbitmap.getconfig()); canvas canvas = new canvas(copybitmap); paint paint = new paint(); paint.setcolor(color.black); matrix matrix = new matrix(); matrix.settranslate(100, 100); canvas.drawbitmap(srcbitmap, matrix, paint); iv_dest.setimagebitmap(copybitmap); } /** * 旋转 * */ public void scole(){ bitmap srcbitmap = bitmapfactory.decodefile(/mnt/sdcard/b.jpg); iv_src.setimagebitmap(srcbitmap); bitmap copybitmap = bitmap.createbitmap(srcbitmap.getwidth(), srcbitmap.getheight(), srcbitmap.getconfig()); canvas canvas = new canvas(copybitmap); paint paint = new paint(); paint.setcolor(color.black); matrix matrix = new matrix(); matrix.setrotate(180, srcbitmap.getwidth()/2, srcbitmap.getheight()/2);//绕原点旋转 canvas.drawbitmap(srcbitmap, matrix, paint); iv_dest.setimagebitmap(copybitmap); } /** * 镜面特效/倒影特效 * 原理一样,一个关于x轴旋转,一个关于y轴旋转 */ public void mirror(){ bitmap srcbitmap = bitmapfactory.decodefile(/mnt/sdcard/b.jpg); iv_src.setimagebitmap(srcbitmap); bitmap copybitmap = bitmap.createbitmap(srcbitmap.getwidth(), srcbitmap.getheight(), srcbitmap.getconfig()); canvas canvas = new canvas(copybitmap); paint paint = new paint(); paint.setcolor(color.black); matrix matrix = new matrix(); matrix.setscale(-1, 1); matrix.posttranslate(srcbitmap.getwidth(), 0); canvas.drawbitmap(srcbitmap, matrix, paint); iv_dest.setimagebitmap(copybitmap); }
接下来进入进入今天的主题。安卓下的动画分为三种: 帧动画、view动画(补间动画)、属性动画。下面分别介绍这三种动画。
帧动画:
帧动画是这三种动画中最为普遍的一种,指的是一帧一帧播放的动画。更直白的讲就是快速切换图片的效果。通过animation-list来实现,创建一个drawable 序列,这些drawable 可以按照指定的时间间隔一个一个的显示,也就是顺序播放事先做好的图像。
帧动画使用的基本步骤:
1 . 创建帧动画每帧需要的图片, 放到对应的 drawable-xxx 或drawable 目录中
2 . 在drawable 目录下,创建帧动画 xml 文件,根节点选择 animation-list。oneshot属性表示帧动画的自动执行。 如果为true,表示动画只播放一次停止在最后一帧上,如果设置为false表示动画循环播放。
3. 在java代码中开启动画。设置为 view 的 background 或者 imageview 的 src,然后获取到控件的 animationdrawable 对象,通过 animationdrawable.start() 方法启动动画
下面以火箭的发射为例演示帧动画。
xml文件中的代码:
java代码的实现:
iv = new imageview(this); //开启帧动画 rocket为上述xml文件 iv.setbackgroundresource(r.drawable.rocket); animationdrawable ad = (animationdrawable) iv.getbackground(); ad.start();
属性动画:
android 3.0之后view类增加新的用来记录动画行为的属性,只能运行的android3.0以上的系统也就是说 运行在 api-11 以上的系统。属性动画会改变当前的视图所在的位置,通过动态改变控件的宽、高、坐标等属性而产生的动画效果。
通过控制控件的属性实现动画效果,属性动画比补间动画要更灵活、强大的多。需要注意的是属性动画内部其实并没有区分位移、缩放、透明、旋转等动画,其核心思想只是修改一个控件的属性,我们可以通过修改不同的属性来实现补间动画的4 种效果而已。
属性动画跟补间动画比,属性动画是真正改变了控件的属性,会改变当前的视图所在的位置,因此当控件的位置改变后只要点击到了控件“身上”就能触发onclick 事件。而补间动画则并没用改变控件的真实属性,因此不管属性动画执行后将控件移动到了哪个位置,只能通过点击该控件的原始位置才能触发onclick 事件。
通过xml 文件实现属性动画步骤:
1. 在res 下创建属性动画文件。在res 目录下创建animator 文件夹,然后创建一个objectanimator 资源文件。资源名称自定义即可。
2. 编写属性动画文件。指定属性值。
3. 编写代码使用属性动画文件。通过animatorinflater加载图片资源,指定要显示动画的控件,并开启动画。
属性动画可以通过xml文件实现,但通常属性动画是通过java代码实现。这里仅给出用xml文件实现淡化动画的案例,其他案例均以java代码的方式实现。
java代码的方式实现属性动画。
public class mainactivity extends activity { private imageview iv; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); iv = (imageview) findviewbyid(r.id.iv); } /** * 淡化动画 * @param view */ public void alpha(view view) { objectanimator oa = objectanimator.offloat(iv, alpha, new float[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }); oa.setduration(3000); oa.setrepeatcount(objectanimator.infinite); oa.setrepeatmode(objectanimator.reverse); oa.start(); } /** * 平移动画 * @param view */ public void trans(view view) { objectanimator oa = objectanimator.offloat(iv, translationx, new float[] { 10f, 20f, 30f, 40f, 60f, 80f }); oa.setduration(3000); oa.setrepeatcount(objectanimator.infinite); oa.setrepeatmode(objectanimator.reverse); oa.start(); } /** * 缩放动画 */ public void scale(view view) { objectanimator oa = objectanimator.offloat(iv, scalex, new float[] { 1f, 2f, 3f, 4f, 5f, 6f }); oa.setduration(3000); oa.setrepeatcount(objectanimator.infinite); oa.setrepeatmode(objectanimator.reverse); oa.start(); } /** * 旋转动画 */ public void rotate(view view) { objectanimator oa = objectanimator.offloat(iv, rotationy, new float[] { 90f, 180f, 270f, 360f }); oa.setduration(3000); oa.setrepeatcount(objectanimator.infinite); oa.setrepeatmode(objectanimator.reverse); oa.start(); } /** * 水平平移 + 竖直平移 */ public void set(view view) { animatorset set = new animatorset(); objectanimator oa = objectanimator.offloat(iv, translationx, new float[] { 10f, 20f, 30f, 40f, 60f, 80f }); oa.setduration(3000); objectanimator oa2 = objectanimator.offloat(iv, translationy, new float[] { -10f, -20f, -30f, -40f, -60f, -80f }); oa2.setduration(3000); set.playtogether(oa, oa2); set.start(); } }
xml文件实现淡化效果:
然后在java代码中实现这样一段代码:
public void alpha(view view) { animator animator = animatorinflater.loadanimator(this, r.animator.alpha); animator.settarget(iv); animator.start(); }
view动画:
渐变动画也叫补间动画。补间动画通过对view 的内容进行一系列的图形变换(包括平移、缩放、旋转、改变透明度)来实现动画效果。动画效果的定义可以采用xml 文件来做也可以采用java 代码来做。
使用xml 文件实现view动画的步骤:
1. 在res 目录下创建anim 文件夹。
2. 在anim 文件夹中创建xml文件,文件名可以自定义。
3. 编辑xml文件。定义不同的标签,表示不同的动画效果。alpha表示淡化,
4. 添加java 逻辑代码,使用animationutils 工具类加载xml 文件,获取animation 对象,调用startanimation 让imageview 执行此动画。
view动画中常用属性的含义:
duration 动画时长
fromalpha 起始透明度,1 为完全不透明,0 为完全透明
repeatcount 重复次数,infinite表示无限重复
toalpha 目标透明度
repeatmode 重复模式,restart 为重新开始,reverse表示来回播放
渐变动画在代码中使用的是alphaanimation 类来定义,在xml 文件中使用节点来定义。旋转动画在代码中使用的是rotateanimation 类来定义,在xml 文件中使用节点来定义。伸缩动画在代码中使用的是scaleanimation 类来定义,在xml 文件中使用节点来定义。平移动画在代码中使用的是translateanimation 类来定义,在xml 文件中使用节点来定义。android 提供了animationset 动画集合用于将多种补间动画联合起来一起使用,这样就能实现更多复杂的动画效果。动画集合既可以使用animationset 类来定义也可以在xml 文件中使用节点来定义。任何复杂的动画均是通过简单的动画集合在一起的。
使用编码方式同样可以实现view动画,直接创建相应的动画对象,然后添加相应的属。代使用编码方式实现view动画跟用xml 文件实现view动画其实是一模一样的,无非就是在java代码中设定相关的属性罢了。
使用xml 文件实现view动画的代码:
1 . 在anim文件夹下新建下列文件:
2 . 在java代码中实现下列逻辑:
import android.os.bundle; import android.app.activity; import android.view.menu; import android.view.view; import android.view.animation.animation; import android.view.animation.animationutils; import android.widget.imageview; public class mainactivity extends activity { private imageview iv; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); iv = (imageview) findviewbyid(r.id.iv); } /** * 淡化动画 * @param view */ public void alpha(view view){ animation aa = animationutils.loadanimation(this, r.anim.alpha_demo); iv.startanimation(aa); } /** * 平移动画 * @param view */ public void trans(view view){ animation ta = animationutils.loadanimation(this, r.anim.trans_demo); iv.startanimation(ta); } /** * 缩放动画 */ public void scale(view view){ animation sa = animationutils.loadanimation(this, r.anim.scale_demo); iv.startanimation(sa); } /** * 旋转动画 */ public void rotate(view view){ animation ra = animationutils.loadanimation(this, r.anim.rotate_demo); iv.startanimation(ra); } /** * 旋转 + 放缩 */ public void set(view view){ animation set = animationutils.loadanimation(this, r.anim.set_demo); iv.startanimation(set); } }
使用java代码实现view动画的代码
import android.os.bundle; import android.app.activity; import android.view.menu; import android.view.view; import android.view.animation.alphaanimation; import android.view.animation.animation; import android.view.animation.animationset; import android.view.animation.animationutils; import android.view.animation.rotateanimation; import android.view.animation.scaleanimation; import android.view.animation.translateanimation; import android.widget.imageview; public class mainactivity extends activity { private imageview iv; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); iv = (imageview) findviewbyid(r.id.iv); } /** * 渐变动画 * @param view */ public void alpha(view view) { alphaanimation aa = new alphaanimation(0.0f, 1.0f); aa.setduration(2000); aa.setrepeatcount(animation.infinite); aa.setrepeatmode(animation.reverse); iv.startanimation(aa); } /** * 平移动画 * @param view */ public void trans(view view) { translateanimation ta = new translateanimation( animation.relative_to_self, 0, animation.relative_to_self, 1f, animation.relative_to_self, 0, animation.relative_to_self, 1f); ta.setduration(2000); ta.setrepeatcount(animation.infinite); ta.setrepeatmode(animation.reverse); iv.startanimation(ta); } /** * 缩放动画 */ public void scale(view view) { scaleanimation sa = new scaleanimation(0.2f, 2.0f, 0.2f, 2.0f, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); sa.setduration(2000); sa.setrepeatcount(animation.infinite); sa.setrepeatmode(animation.reverse); iv.startanimation(sa); } /** * 旋转动画 */ public void rotate(view view) { rotateanimation ra = new rotateanimation(0, 360, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); ra.setduration(2000); ra.setrepeatcount(animation.infinite); ra.setrepeatmode(animation.reverse); iv.startanimation(ra); } /** * 旋转 + 平移 + 放缩 * animationset添加各个动画 */ public void set(view view) { animationset set = new animationset(false); rotateanimation ra = new rotateanimation(0, 360, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); ra.setduration(2000); ra.setrepeatcount(animation.infinite); ra.setrepeatmode(animation.reverse); scaleanimation sa = new scaleanimation(0.2f, 2.0f, 0.2f, 2.0f, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); sa.setduration(2000); sa.setrepeatcount(animation.infinite); sa.setrepeatmode(animation.reverse); translateanimation ta = new translateanimation( animation.relative_to_self, 0, animation.relative_to_self, 1f, animation.relative_to_self, 0, animation.relative_to_self, 1f); ta.setduration(2000); ta.setrepeatcount(animation.infinite); ta.setrepeatmode(animation.reverse); set.addanimation(ta); set.addanimation(sa); set.addanimation(ra); iv.startanimation(set); } }
自此android下的三种动画全部讲解完毕。