经过前两章的学习,终于到了我们使用最多的属性动画了。属性动画是Android3.0(API 11)中引入的新的动画机制,相较于补间动画,它除了可以实现补间动画的所有效果外,还能实现补间动画无法做到的效果,比如我们现在要求一张图片背景色渐变,补间动画就无法完成,而使用属性动画就可以很简单的实现这个效果。另外补间动画只能作用在View上,而不能作用于非View的对象上,比如我们自定义一个View,此View的位置我们由Ponit类(包含x、y轴坐标信息),我们要求使用动画改变View的位置,就需要使用动画操作point对象,那么就只能使用属性动画来完成。对于补间动画来说,我们之前就已经讲过了,动画只会改变View的绘制位置而不会改变其真正属性,所以像触摸事件不会跟随动画移动,就会出现view平移后点击事件仍然留在原地的尴尬事情,而我们要介绍的属性动画就没有这个问题,因为是直接操作的View的属性,因此在其移动后,相应的事件也会随之移动。
属性动画中我们使用较多的两个类,一个是ValueAnimator,另一个是ObjectAnimator,其中后者继承前者,并且封装了许多常用操作,因此比前者更加易用。ValueAnimator的父类则是Animator,Animator还有一个常用子类是AnimatorSet(动画集合),这个我们也会在后面介绍。
ok,讲了这么多废话,都不如代码直观,下面我们就来讲解ValueAnimator、ObjectAnimator以及AnimatorSet的简单使用:
ValueAnimator
先上用法:
alphaValueAnimator = ValueAnimator.ofFloat(1.0f,0f);
alphaValueAnimator.setDuration(1000);
alphaValueAnimator.setRepeatCount(1);
alphaValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
alphaValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
ivContainer.setAlpha((float)animation.getAnimatedValue());
}
});
我们这里写了一个渐隐渐现的动画,动画透明度从1变到0,再从0变到1,然后结束。可以看到使用方法里和补间动画有很多相似的地方,例如设置动画时间(setDuration)、设置重复次数(setRepeatCount)、设置重复模式(setRepeatMode)等等。其中ValueAnimator的of…方法中,前者是动画初始值,后者是动画结束值,你也可以传多个参数,例如:
ValueAnimator.ofFloat(1.0f,0.5f,1f,0f);
就带便透明度从1变化为0.5再变化为1再变化为0的动画。
ValueAnimator支持的其他常用方法还有ofInt()、ofArgb()、ofObject()、ofPropertyValueHolder(),前两个方法使用和ofFloat大致类似,后两个方法我们留在后面在分析属性动画执行流程时会进行讲解。
需要注意的是addUpdateListenr方法,这个方法为动画执行加了坚听,我们可以在onAnimationUpdate方法中对我们要执行动画的对象进行更改。如果想观察动画执行过程的,可以在onAnimationUpdate方法中打印animation.getAnimatedValue的值查看变化过程,可以对ValueAnimator加深理解,我在这里就不再演示。如果我们用到了其他效果,可以相应在onAnimationUpdate方法中写下对应逻辑。用法比较简单,不多说。
下面是我们使用ValueAnimator实现的动画效果,如图:
ObjectAnimator
ObjectAnimator的使用就比上面的要简单的多,写法是这样的:
float translationX = ivContainer.getTranslationX();
translateObjectAnimator = ObjectAnimator.ofFloat(ivContainer,"translationY",translationX,translationX-200);
translateObjectAnimator.setRepeatCount(1);
translateObjectAnimator.setRepeatMode(ValueAnimator.REVERSE);
translateObjectAnimator.setDuration(1000);
上面的效果是将ImageView向上平移200像素再平移回原位置(如果不设置repeatCount则平移后会留在原位置,这里为了方便演示设置了1个重复次数并且设置重复方式为反转)。可以看出ObjectAnimator的使用要比他的父类简单许多,ofFloat方法中,第一个参数Target接受一个Object对象,这是动画执行的对象,第二个参数propertyName是动画执行过程选中要改变的对象中的值,注意这个属性名在响应的对象里必须有setter和getter方法,其余参数则是动画执行的初始值和结束值,其余与ValueAnimator类似。
我们在对view添加动画的时候,可以使用的PropertyName都有哪些,常用的有“translationY”、”rotation”、”tranlationX”、”alpha”、”scale”等等。
使用ObjectAnimator我们就不必再添加动画监听来设置给目标对象,在调用start()方法后内部会自动进行调用,后续我们会进行详细的分析。
执行效果如下图:
AnimatorSet(动画集合)
AnimatorSet也是继承于Animator,主要用于组合动画如同时播放两个动画,或者之后播放,提前播放动画、延迟播放等等,主要用到的方法有:
play(Animator anim) //播放当前动画
after(Animator anim) //将该动画插入原动画之前
after(long delay) //将动画延迟相应毫秒
before(Animator anim) //将该动画放入原动画
with(Animator anim) //将该动画与原动画同时播放
上述方法返回的都是Animator.Builder对象,有了这些方法,我们对view进行组合操作如下:
animatorValueSet = new AnimatorSet();
animatorValueSet.play(alphaValueAnimator)
.with(rotateValueAnimator)
.before(scaleValueAnimator)
.after(translateValueAnimator);
可以看到,该动画会先执行translateValueAnimator,然后同时执行alphaValueAnimator和rotateValueAnimator,最后执行scaleValueAnimator。
下面是分别使用ValueAnimator和ObjectAnimator来使用集合动画(其实没什么卵区别):
监听动画开始与结束
有时我们会有在动画结束或开始时执行某些方法的需求,这时候需要我们对动画进行监听。上面我们已经用过了监听动画状态更新的监听器,另外还有addListener和addPauseListener,分别监听动画的开始结束等状态和停止状态。
animatorObjectSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//动画开始时调用
}
@Override
public void onAnimationEnd(Animator animation) {
//动画结束时调用
}
@Override
public void onAnimationCancel(Animator animation) {
//动画取消时调用
}
@Override
public void onAnimationRepeat(Animator animation) {
//动画重复执行时调用
}
});
我们可以在几个方法中来进行逻辑操作,有时候我们并不想监听这么多状态,那么就可以使用AnimatorListenerAdapter这个抽象类,该类实现了AnimatorListener和AnimatorPauseListener,我们可以按照自己需要来复写相应方法:
animatorObjectSet.addListener(new AnimatorListenerAdapter() {
});
xml编写属性动画
我们知道,补间动画可以有两种形式来实现,一种是xml形式,另一种是代码形式。属性动画我们刚刚讲了代码的实现形式,那么它可不可以写进xml中呢,答案是肯定的。
属性动画所在的目录是res/animator下,如果res下没有animator,可以新建该目录,新建xml文件,其中我们可以使用的根节点有这么三个:
我这里实现的效果是这样的:
实现的效果和Java代码一样,需要注意set的属性ordering,together为同时执行,sequentially为顺序执行。
在程序中调用这个动画的方法是:
/**
* xml实现动画
*/
protected void xmlAnimatorTest (View view) {
Animator animator = AnimatorInflater.loadAnimator(this,R.animator.animator_test);
animator.setTarget(ivContainer);
animator.start();
}
实现的效果如图所示:
ok,到这里属性动画的基本用法就讲完了,接下来将会介绍Animator的底层实现和一些高级用法以及酷炫的动画特效,代码地址依然是:github,欢迎查看。
也欢迎来我的博客来探讨相关技术~
enjoy~