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