引子


   Android提供了:View Animation 、Drawable Animation 、Property Animation 三种类型的动画。其中View Animation(也叫做渐变动画或者补间动画)支持:平移、旋转、透明度、缩放4种方式。Drawable Animation(也叫做帧动画)就更简单了,原理就是我们将一组图片排好顺序,依次执行。但是在使用过程中慢慢的发现,前两种动画有时候并不能满足我们的需求,比如我们想让View的背景能渐变。因此Google从android3.0开始推出了Property Animation(也叫做属性动画),它是通过动态改变对象的属性,用来弥补前两种动画的不足,由于前两种动画相对简单,我们这里重点介绍属性动画。

ValueAnimator


    ValueAnimator是整个属性动画中最核心的一个类,因为属性动画的运行机制就是通过不断的对属性值进行操作,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类负责计算的,它的内部使用一种时间循环的机制来计算值与值之间的动画过渡。我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。

  我们来看看ValueAnimator如何使用,其实使用比较简单:

1         ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight - imageView.getHeight());
 2         animator.setTarget(imageView);
 3         animator.setDuration(1000).start();
 4 
 5         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
 6             @Override
 7             public void onAnimationUpdate(ValueAnimator animation) {
 8                 imageView.setTranslationY((Float) animation.getAnimatedValue());
 9             }
10         });

ofFloat是可变参数,可以传多个参数,上面例子中传了两个参数,也就是从0过渡到指定的高度值。

addUpdateListener是为动画添加一个监听器,在动画执行过程中它会不停的回调,这里通过animation.getAnimatedValue()拿到的值就是在ofFloat传进去的值[0,mScreenHeight - imageView.getHeight()]。

  ValueAnimator最常用的方法就是ofInt和ofFloat,此外还有一些可能会用到的方法,比如:

  setStartDelay()用于设置动画延迟执行

      setRepeatCount(int)用于设置重复的次数,参数为-1表示执行无限次。

  setRepeatMode(int)用于设置重复的模式,包括RESTART(重新播放)和REVERSE(倒序播放)两种模式。

  setInterpolator(TimeInterpolator value)用来设置动画的运行速率,其中TimeInterpolator是为了支持属性动画才增加的接口,它也有很多的实现类,我们经常用的比如:AccelerateDecelerateInterpolator(先加速后减速)、LinearInterpolator(匀速)、AccelerateInterpolator(加速)、DecelerateInterpolator(减速)等等。

  setEvaluator(TypeEvaluator value)用来估算当前动画的执行情况,并将值返回给监听器,我们上面提到的在onAnimationUpdate回调中拿到值animation.getAnimatedValue()

就是通过这里返回的。还是直接来段代码看一下:

1         animator.setEvaluator(new TypeEvaluator() {
 2             @Override
 3             public Object evaluate(float fraction, Object startValue, Object endValue) {
 4                 Log.e(TAG, fraction * 3 + "");
 5                 PointF point = new PointF();
 6                 point.x = 200 * fraction * 3;
 7                 point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
 8                 return point;
 9             }
10         });

fraction值的是进度,也就是当前动画播放了多少了。TypeEvaluator有三个实现类:ArgbEvaluator(颜色渐变)、FloatEvaluator、IntEvaluator具体用哪个是由传进来的初始值的类型决定的。

其他的方法就不一一的列出来了,使用的时候可以查看API文档。

ObjectAnimator


  ObjectAnimator继承自ValueAnimator,不过却对我们来说更常用一些,因为ValueAnimator更像是动画的底层驱动,完成计算动画的各种数字,而ObjectAnimator更像是上层的接口,我们可以直接调用来操作View的属性,然后其他事情交给ValueAnimator去处理。

  我们还是先来一段代码看看ObjectAnimator和ValueAnimator的使用有什么区别,其实他们之间的使用比较相似(毕竟是父子类关系)。

1         ObjectAnimator//
2                 .ofFloat(view, "rotationX", 0.0F, 360.0F)//
3                 .setDuration(500)//
4                 .start();

从代码我们看出多了两个参数:第一个参数需要传一个View,也就是需要把动画加到哪个View上面。

                                        第二个参数是要修改属性的名字。这里rotationX表示围绕View的水平轴转动。

不过我们得注意的是,这里的属性要满足两个条件:

  • 属性必须有get和set方法。因为在动画过程中需要不停的刷新view的属性值。
  • 在调用set方法时,必须能够在UI上有所体现,就是对View进行操作。

这听起来可能有些抽象,不过你去View类中看看就明白了,setRotation()、getRotation()、setTranslationX()、getTranslationX()、setScaleY()、getScaleY()这些方法都是存在的。另外第二个参数其实是可以填任意值的,然后在onAnimationUpdate回调中可以设置自己想要的效果。

其他方法在ValueAnimator中都介绍过了。。。

 

AnimatorSet


  AnimatorSet顾名思义就是组合动画,可以将一些个动画,组装成一系列的动画。我们直接看它的一些常用方法好了:

     一、AnimatorSet提供了一个play(Animator anim)方法,返回的是一个AnimatorSet.Builder类,它包括四个方法:

  • after(Animator anim)   将现有动画插入到传入的动画之后执行
  • after(long delay)   将现有动画延迟指定毫秒后执行
  • before(Animator anim)   将现有动画插入到传入的动画之前执行
  • with(Animator anim)   将现有动画和传入的动画同时执行

 二、其他方法

  • playTogether(Animator... items)将多个动画同时执行。
  • playSequentially(Animator... items) 顺序的执行多个动画。
  • setTarget(Object target)设置要运行动画的Target。

Animator监听器


 

  有些时候,我们希望可以监听到动画的各种事件,比如动画何时开始,何时结束,然后在开始或者结束的时候去执行一些逻辑处理。Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。

1         animator.addListener(new Animator.AnimatorListener() {
 2             @Override
 3             public void onAnimationStart(Animator animation) {
 4                 //当动画开始的时候调用
 5             }
 6 
 7             @Override
 8             public void onAnimationEnd(Animator animation) {
 9                 //当动画结束时调用
10             }
11 
12             @Override
13             public void onAnimationCancel(Animator animation) {
14                 //当动画取消时调用
15             }
16 
17             @Override
18             public void onAnimationRepeat(Animator animation) {
19                 //当动画重复执行时调用
20             }
21         });

不过有时候并不需要四个方法全部都实现,因此系统就提供了一个适配抽象类AnimatorListenerAdapter,这样我们就可以根据自己的需要实现指定方法就可以了。

1 anim.addListener(new AnimatorListenerAdapter() {  
2     @Override  
3     public void onAnimationEnd(Animator animation) {  
4     }  
5 });

 

用XML写属性动画


  属性动画除了能用代码写,也是可以用xml来写的,用xml重用性会好一些,我们可以将一些公共的动画抽象出来。我们这里就简单介绍下,不详细的去了解了:

  它有三种标签:

  • <animator>  对应代码中的ValueAnimator
  • <objectAnimator>  对应代码中的ObjectAnimator
  • <set>  对应代码中的AnimatorSet

我们直接上代码来实现一个组合动画:

1 <set xmlns:android="http://schemas.android.com/apk/res/android"  
 2     android:ordering="sequentially" >  
 3   
 4     <objectAnimator  
 5         android:duration="2000"  
 6         android:propertyName="translationX"  
 7         android:valueFrom="-500"  
 8         android:valueTo="0"  
 9         android:valueType="floatType" >  
10     </objectAnimator>  
11   
12     <set android:ordering="together" >  
13         <objectAnimator  
14             android:duration="3000"  
15             android:propertyName="rotation"  
16             android:valueFrom="0"  
17             android:valueTo="360"  
18             android:valueType="floatType" >  
19         </objectAnimator>  
20   
21         <set android:ordering="sequentially" >  
22             <objectAnimator  
23                 android:duration="1500"  
24                 android:propertyName="alpha"  
25                 android:valueFrom="1"  
26                 android:valueTo="0"  
27                 android:valueType="floatType" >  
28             </objectAnimator>  
29             <objectAnimator  
30                 android:duration="1500"  
31                 android:propertyName="alpha"  
32                 android:valueFrom="0"  
33                 android:valueTo="1"  
34                 android:valueType="floatType" >  
35             </objectAnimator>  
36         </set>  
37     </set>  
38   
39 </set>

然后在java代码中通过下面的代码调用:

1 Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);  
2 animator.setTarget(view);  
3 animator.start();

这样就完成了一个动画,感觉xml动画的逻辑性还是挺清晰的。

好了,属性动画大致就先整理这么多内容,上面提到的很多方法没必要都去背下来,在项目中真正用到的时候,查阅下文档就可以了。一般复杂的动画可以拆解成一个个小动画,然后再组装起来就实现了,还必须多实践才行。