android之animator 和animation 的区别
发布时间:2025-05-11 18:13:30 发布人:远客网络
一、android之animator 和animation 的区别
Animator框架是Android 4.0中新添加的一个动画框架,和之前的Animation框架相比,Animator可以进行更多和更精细化的动画控制,而且比之前更简单和更高效。在4.0源码中随处都可以看到Animator的使用。
如下图,是Animation和Animator两个类继承图的对比。
C:AlphaAnimation C:AnimatorSet
C:AnimationSet C:ValueAnimator
C:DummyAnimation C:ObjectAnimator
C:Rotate3dAnimation C:TimeAnbimator
Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是一个整个View动画,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源。
在Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性值,多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下减少CPU资源消耗。
Animator框架封装得比较完美,对外提供的接口非常简单,创建一个ObjectAnimator只需通过如下图所示的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字,但这个属性必须有get和set函数,内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值,最终值,还可以调用setInterpolator设置曲线函数。
AnimatorSet主要是组合多个AnimatorSet和ObjectAnimator形成一个动画,并可以控制动画的播放顺序,其中还有个辅助类通过调用play函数获得。
通过实现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;
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(),
squashAnim1.setDuration(duration/4);
squashAnim1.setRepeatCount(1);
squashAnim1.setRepeatMode(ValueAnimator.REVERSE);
squashAnim1.setInterpolator(new DecelerateInterpolator());
ValueAnimator squashAnim2= ObjectAnimator.ofFloat(newBall,"width", newBall.getWidth(),
squashAnim2.setDuration(duration/4);
squashAnim2.setRepeatCount(1);
squashAnim2.setRepeatMode(ValueAnimator.REVERSE);
squashAnim2.setInterpolator(new DecelerateInterpolator());
ValueAnimator stretchAnim1= ObjectAnimator.ofFloat(newBall,"y", endY,
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,
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.addListener(new AnimatorListenerAdapter(){
public void 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);
二、android中的动画有哪几类
在Android3.0(即API Level11)以前,Android仅支持2种动画:分别是Frame Animation(逐帧动画)和Tween Animation(补间动画),在3.0之后Android支持了一种新的动画系统,称为:Property Animation(属性动画)。
一、Frame Animation:(逐帧动画)
这个很好理解,一帧帧的播放图片,利用人眼视觉残留原理,给我们带来动画的感觉。它的原理的GIF图片、电影播放原理一样。
1.定义逐帧动画比较简单,只要在中使用子元素定义所有播放帧即可。
(1) android:oneshot设置是否仅播放一次
(2) android:drawable设置每一帧图片
(3) android:duration设置图片间切换间隔
2.习惯上把AnimationDrawable设置为ImageView的背景
android:background=@anim/frame_anim
然后我们就可以在java代码中获取AnimationDrawable对象了
AnimationDrawable anim=(AnimationDrawable)imageView.getBackground();
(需要注意的是,AnimationDrawable默认是不播放的,调用其start()方法开始播放,stop停止播放)
3.上面的动画文件是通过xml文件来配置的,如果你喜欢,也可以通过在java代码中创建AnimationDrawable对象,然后通过addFrame(Drawable frame, int duration)方法向动画添加帧,然后start()。。。
二、Tween Animation:(补间动画)
补间动画就是我们只需指定开始、结束的“关键帧“,而变化中的其他帧由系统来计算,不必自己一帧帧的去定义。
1. Android使用Animation代表抽象动画,包括四种子类:AlphaAnimation(透明度动画)、ScaleAnimation(缩放动画)、TranslateAnimation(位移动画)、RotateAnimation(透明度动画)。Android里面允许在java中创建Animation类对象,但是一般都会采用动画资源文件来定义动画,把界面与逻辑分离
<set android:interpolator="@android:anim/linear_interpolator" xmlns:android="">
<rotate android:duration="3000/" android:fromdegrees="0" android:pivotx="50%" android:pivoty="50%" android:todegrees="1800">
</rotate></alpha></set>
(一个set可以同时定义多个动画,一起执行。)
2. android:interpolator=@android:anim/linear_interpolator控制动画期间需要补入多少帧,简单来说就是控制动画速度,有些地方翻译为“插值“。Interpolator有几种实现类:LinearInterpolator、AccelerateInterpolator、AccelerateDecelerateInterpolator、CycleInterpolator、DecelerateInterpolator,具体使用可以参考官方API Demo。
3.定义好anim文件后,我们可以通过AnimationUtils工具类来加载它们,加载成功后返回一个Animation。然后就可以通过View的startAnimation(anim)开始执行动画了。
Animation anim= AnimationUtils.loadAnimation(this, R.anim.anim);
anim.setInterpolator(interpolator);
三、Property Animation:(属性动画)
属性动画,这个是在Android 3.0中才引进的,它可以直接更改我们对象的属性。在上面提到的Tween Animation中,只是更改View的绘画效果而View的真实属性是不改变的。假设你用Tween动画将一个Button从左边移到右边,无论你怎么点击移动后的Button,他都没有反应。而当你点击移动前Button的位置时才有反应,因为Button的位置属性木有改变。而Property Animation则可以直接改变View对象的属性值,这样可以让我们少做一些处理工作,提高效率与代码的可读性。
(1)ValueAnimator:包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用ValueAnimator有两个步骤
2根据属性值执行相应的动作,如改变对象的某一属性。
我们的主是第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),将要改变View对象属性的事情在该接口中do。
animation.addUpdateListener(new AnimatorUpdateListener(){
public void onAnimationUpdate(ValueAnimator animation){
(2)ObjectAnimator:继承自ValueAnimator,要指定一个对象及该对象的一个属性,当属性值计算完成时自动设置为该对象的相应属性,即完成了Property Animation的全部两步操作。实际应用中一般都会用ObjectAnimator来改变某一对象的某一属性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,应该满足以下条件:
1.对象应该有一个setter函数:set(驼峰命名法)
2如下面的例子,像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法:get
3如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。
ObjectAnimator oa=ObjectAnimator.ofFloat(tv, alpha, 0f, 1f);
如果不满足上面的条件,我们只能乖乖的使用ValueAnimator来创建动画。
(3)Animator.AnimatorListener:可以为Animator设置动画监听,需要重写下面四个方法。
这里我们也可以实现AnimatorListenerAdapter,他的好处是可以只用定义想监听的事件而不用实现每个函数却只定义一空函数体。如下:
anim.addListener(new AnimatorListenerAdapter(){
public void on AnimationEnd(Animator animation){
(4)AnimationSet:可以组合多个动画共同工作
AnimatorSet bouncer= new AnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
上面的代码意思是:首先播放anim1;同时播放anim2,anim3,anim4;最后播放anim5。
(5)TimeInterplator:与Tween中的interpolator类似。有以下几种
AccelerateInterpolator加速,开始时慢中间加速
DecelerateInterpolator减速,开始时快然后减速
AccelerateDecelerateInterolator先加速后减速,开始结束时慢,中间加速
AnticipateInterpolator反向,先向相反方向改变一段再加速播放
AnticipateOvershootInterpolator反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
BounceInterpolator跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
CycleIinterpolator循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2* mCycles* Math.PI* input)
LinearInterpolator线性,线性均匀改变
OvershottInterpolator回弹,最后超出目的值然后缓慢改变到目的值
TimeInterpolator一个接口,允许你自定义interpolator,以上几个都是实现了这个接口
(6)Keyframes:可以让我们定义除了开始和结束以外的关键帧。KeyFrame是抽象类,要通过ofInt(),ofFloat(),ofObject()获得适当的KeyFrame,然后通过PropertyValuesHolder.ofKeyframe获得PropertyValuesHolder对象,如下:
Keyframe kf0= Keyframe.ofInt(0, 400);
Keyframe kf1= Keyframe.ofInt(0.25f, 200);
Keyframe kf2= Keyframe.ofInt(0.5f, 400);
Keyframe kf4= Keyframe.ofInt(0.75f, 100);
Keyframe kf3= Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation= PropertyValuesHolder.ofKeyframe(width, kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim= ObjectAnimator.ofPropertyValuesHolder(btn, pvhRotation);
上述代码的意思是:设置btn对象的width属性值使其:开始时 Width=400,动画开始1/4时 Width=200,动画开始1/2时 Width=400,动画开始3/4时 Width=100,动画结束时 Width=500。
(7)ViewPropertyAnimator:对一个View同时改变多种属性,非常推荐用这种。该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图。而且使用起来非常简便,但是要求API LEVEL 12,即Android 3.1以上。仅需要一行代码即可完成水平、竖直移动
myView.animate().translationX(50f). translationY(100f);
translationX,translationY: View相对于原始位置的偏移量
rotation,rotationX,rotationY:旋转,rotation用于2D旋转角度,3D中用到后两个
x,y: View的最终坐标,是View的left,top位置加上translationX,translationY
四、最后自己总结一下这三种动画的优缺点:
(1)Frame Animation(帧动画)主要用于播放一帧帧准备好的图片,类似GIF图片,优点是使用简单方便、缺点是需要事先准备好每一帧图片;
(2)Tween Animation(补间动画)仅需定义开始与结束的关键帧,而变化的中间帧由系统补上,优点是不用准备每一帧,缺点是只改变了对象绘制,而没有改变View本身属性。因此如果改变了按钮的位置,还是需要点击原来按钮所在位置才有效。
(3)Property Animation(属性动画)是3.0后推出的动画,优点是使用简单、降低实现的复杂度、直接更改对象的属性、几乎可适用于任何对象而仅非View类,缺点是需要3.0以上的API支持,限制较大!但是目前国外有个开源库,可以提供低版本支持!
三、animation和animator的区别
Animator框架是Android 4.0中新添加的一个动画框架,和之前的Animation框架相比,Animator可以进行更多和更精细化的动画控制,而且比之前更简单和更高效。在4.0源码中随处都可以看到Animator的使用。
如下图,是Animation和Animator两个类继承图的对比。
C:AlphaAnimation C:AnimatorSet
C:AnimationSet C:ValueAnimator
C:DummyAnimation C:ObjectAnimator
C:Rotate3dAnimation C:TimeAnbimator
Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是一个整个View动画,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧,如果动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程中的帧之间间隙时间是绘制函数所消耗的时间,可能会导致动画消耗比较多的CPU资源。
在Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化控制,只控制一个对象的一个属性值,多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjectAnimator能够自动驱动,可以调用setFrameDelay(longframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提下减少CPU资源消耗。
Animator框架封装得比较完美,对外提供的接口非常简单,创建一个ObjectAnimator只需通过如下图所示的静态工厂类直接返回一个ObjectAnimator对象。传的参数包括一个对象和对象的属性名字,但这个属性必须有get和set函数,内部会通过java反射机制来调用set函数修改对象属性值。还包括属性的初始值,最终值,还可以调用setInterpolator设置曲线函数。
AnimatorSet主要是组合多个AnimatorSet和ObjectAnimator形成一个动画,并可以控制动画的播放顺序,其中还有个辅助类通过调用play函数获得。
通过实现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;
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(),
squashAnim1.setDuration(duration/4);
squashAnim1.setRepeatCount(1);
squashAnim1.setRepeatMode(ValueAnimator.REVERSE);
squashAnim1.setInterpolator(new DecelerateInterpolator());
ValueAnimator squashAnim2= ObjectAnimator.ofFloat(newBall,"width", newBall.getWidth(),
squashAnim2.setDuration(duration/4);
squashAnim2.setRepeatCount(1);
squashAnim2.setRepeatMode(ValueAnimator.REVERSE);
squashAnim2.setInterpolator(new DecelerateInterpolator());
ValueAnimator stretchAnim1= ObjectAnimator.ofFloat(newBall,"y", endY,
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,
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.addListener(new AnimatorListenerAdapter(){
public void 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);