一、            前言

Animator框架是Android 4.0中新添加的一个动画框架,和之前的Animation框架相比,Animator可以进行更多和更精细化的动画控制,而且比之前更简单和更高效。在4.0源码中随处都可以看到Animator的使用。

 

二、            Animation和Animator比较

如下图,是Animation和Animator两个类继承图的对比。

Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是一个整个View动画,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源。

在Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性值,多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下减少CPU资源消耗。

三、            关键接口介绍

1.      ObjectAnimator介绍

Animator框架封装得比较完美,对外提供的接口非常简单,创建一个ObjectAnimator只需通过如下图所示的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字,但这个属性必须有get和set函数,内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值,最终值,还可以调用setInterpolator设置曲线函数。

2.      AnimatorSet介绍

AnimatorSet主要是组合多个AnimatorSet和ObjectAnimator形成一个动画,并可以控制动画的播放顺序,其中还有个辅助类通过调用play函数获得。

3.   AnimatorUpdateListner介绍

通过实现AnimatorUpdateListner,来获得属性值发生变化时的事件,在这个回调中发起重绘屏幕事件。

 

四、            使用实例

在Android4.0中的ApiDemo中有个BouncingBalls实例,描述了Animator框架的使用,当点击屏幕时,绘制一个球从点击位置掉到屏幕底部,碰到底部时球有压扁的效果,然后回弹到点击位置再消失。

代码如下:

ShapeHolder newBall =addBall(event.getX(), event.getY());
 
// Bouncing animation with squash and stretch
           float startY = newBall.getY();
           float endY = getHeight() - 50f;
           float h = (float)getHeight();
           float eventY = event.getY();
           int duration = (int)(500 * ((h - eventY)/h));
           ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall,"y", startY, endY);
           bounceAnim.setDuration(duration);
           bounceAnim.setInterpolator(new AccelerateInterpolator());
           ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall,"x", newBall.getX(),
                    newBall.getX() - 25f);
           squashAnim1.setDuration(duration/4);
           squashAnim1.setRepeatCount(1);
           squashAnim1.setRepeatMode(ValueAnimator.REVERSE);
            squashAnim1.setInterpolator(new DecelerateInterpolator());
           ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall,"width", newBall.getWidth(),
                    newBall.getWidth() + 50);
           squashAnim2.setDuration(duration/4);
           squashAnim2.setRepeatCount(1);
           squashAnim2.setRepeatMode(ValueAnimator.REVERSE);
           squashAnim2.setInterpolator(new DecelerateInterpolator());
           ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall,"y", endY,
                    endY + 25f);
           stretchAnim1.setDuration(duration/4);
           stretchAnim1.setRepeatCount(1);
           stretchAnim1.setInterpolator(new DecelerateInterpolator());
           stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);
           ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall,"height",
                    newBall.getHeight(),newBall.getHeight() - 25);
           stretchAnim2.setDuration(duration/4);
           stretchAnim2.setRepeatCount(1);
           stretchAnim2.setInterpolator(new DecelerateInterpolator());
           stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);
           ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall,"y", endY,
                    startY);
            bounceBackAnim.setDuration(duration);
           bounceBackAnim.setInterpolator(newDecelerateInterpolator());
// Sequence the down/squash&stretch/upanimations
           AnimatorSet bouncer = new AnimatorSet();
           bouncer.play(bounceAnim).before(squashAnim1);
           bouncer.play(squashAnim1).with(squashAnim2);
           bouncer.play(squashAnim1).with(stretchAnim1);
           bouncer.play(squashAnim1).with(stretchAnim2);
           bouncer.play(bounceBackAnim).after(stretchAnim2);
 
// Fading animation - remove the ball when theanimation is done
           ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall,"alpha", 1f, 0f);
           fadeAnim.setDuration(250);
           fadeAnim.addListener(new AnimatorListenerAdapter() {
@Override
               publicvoid onAnimationEnd(Animatoranimation) {
balls.remove(((ObjectAnimator)animation).getTarget());
 
               }
           });
// Sequence the two animations to play oneafter the other
           AnimatorSet animatorSet = new AnimatorSet();
           animatorSet.play(bouncer).before(fadeAnim);
 
// Start the animation
           animatorSet.start();


一、            前言

Animator框架是Android 4.0中新添加的一个动画框架,和之前的Animation框架相比,Animator可以进行更多和更精细化的动画控制,而且比之前更简单和更高效。在4.0源码中随处都可以看到Animator的使用。

 

二、            Animation和Animator比较

如下图,是Animation和Animator两个类继承图的对比。

Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是一个整个View动画,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源。

在Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性值,多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下减少CPU资源消耗。

三、            关键接口介绍

1.      ObjectAnimator介绍

Animator框架封装得比较完美,对外提供的接口非常简单,创建一个ObjectAnimator只需通过如下图所示的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字,但这个属性必须有get和set函数,内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值,最终值,还可以调用setInterpolator设置曲线函数。

2.      AnimatorSet介绍

AnimatorSet主要是组合多个AnimatorSet和ObjectAnimator形成一个动画,并可以控制动画的播放顺序,其中还有个辅助类通过调用play函数获得。

3.   AnimatorUpdateListner介绍

通过实现AnimatorUpdateListner,来获得属性值发生变化时的事件,在这个回调中发起重绘屏幕事件。

 

四、            使用实例

在Android4.0中的ApiDemo中有个BouncingBalls实例,描述了Animator框架的使用,当点击屏幕时,绘制一个球从点击位置掉到屏幕底部,碰到底部时球有压扁的效果,然后回弹到点击位置再消失。

代码如下:

ShapeHolder newBall =addBall(event.getX(), event.getY());
 
// Bouncing animation with squash and stretch
           float startY = newBall.getY();
           float endY = getHeight() - 50f;
           float h = (float)getHeight();
           float eventY = event.getY();
           int duration = (int)(500 * ((h - eventY)/h));
           ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall,"y", startY, endY);
           bounceAnim.setDuration(duration);
           bounceAnim.setInterpolator(new AccelerateInterpolator());
           ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall,"x", newBall.getX(),
                    newBall.getX() - 25f);
           squashAnim1.setDuration(duration/4);
           squashAnim1.setRepeatCount(1);
           squashAnim1.setRepeatMode(ValueAnimator.REVERSE);
            squashAnim1.setInterpolator(new DecelerateInterpolator());
           ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall,"width", newBall.getWidth(),
                    newBall.getWidth() + 50);
           squashAnim2.setDuration(duration/4);
           squashAnim2.setRepeatCount(1);
           squashAnim2.setRepeatMode(ValueAnimator.REVERSE);
           squashAnim2.setInterpolator(new DecelerateInterpolator());
           ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall,"y", endY,
                    endY + 25f);
           stretchAnim1.setDuration(duration/4);
           stretchAnim1.setRepeatCount(1);
           stretchAnim1.setInterpolator(new DecelerateInterpolator());
           stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);
           ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall,"height",
                    newBall.getHeight(),newBall.getHeight() - 25);
           stretchAnim2.setDuration(duration/4);
           stretchAnim2.setRepeatCount(1);
           stretchAnim2.setInterpolator(new DecelerateInterpolator());
           stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);
           ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall,"y", endY,
                    startY);
            bounceBackAnim.setDuration(duration);
           bounceBackAnim.setInterpolator(newDecelerateInterpolator());
// Sequence the down/squash&stretch/upanimations
           AnimatorSet bouncer = new AnimatorSet();
           bouncer.play(bounceAnim).before(squashAnim1);
           bouncer.play(squashAnim1).with(squashAnim2);
           bouncer.play(squashAnim1).with(stretchAnim1);
           bouncer.play(squashAnim1).with(stretchAnim2);
           bouncer.play(bounceBackAnim).after(stretchAnim2);
 
// Fading animation - remove the ball when theanimation is done
           ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall,"alpha", 1f, 0f);
           fadeAnim.setDuration(250);
           fadeAnim.addListener(new AnimatorListenerAdapter() {
@Override
               publicvoid onAnimationEnd(Animatoranimation) {
balls.remove(((ObjectAnimator)animation).getTarget());
 
               }
           });
// Sequence the two animations to play oneafter the other
           AnimatorSet animatorSet = new AnimatorSet();
           animatorSet.play(bouncer).before(fadeAnim);
 
// Start the animation
           animatorSet.start();