如何使用ValueAnimator
ValueAnimator类通过指定一组整数,浮点数,或色彩值,以及动画的持续时间来定义。获得一个ValueAnimator对象的实例需要调用它的一个工厂方法:ofint(),offloat() ,或者ofobject(),如下所示:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();
在这段代码中,当start()方法开始运行时,ValueAnimator开始计算在0f和1f之间动画的值,动画的持续时间为1000毫秒。
你也可以指定一个自定义类型的动画如下所示:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();
在这段代码中,当start()方法开始运行时,ValueAnimator开始根据MyTypeEvaluator计算在startpropertyvalue和endpropertyvalue的值,动画的持续时间为1000毫秒。
上面的代码片段,对于某个对象来说,并没有实际的效果,因为ValueAnimator类并不直接对象或属性产生影响。你所需要做的是根据计算得到的值来改变对象的某些属性。你可以通过监听ValueAnimator在动画生命周期中的接口来处理逻辑,比如帧更新。在实现接口时,你可以通过调用getAnimatedValue()来得到特定帧的计算值。
如何使用ObjectAnimator
ObjectAnimator是ValueAnimator的子类,该类会根据计算所得到的数值来直接对预先指定的对象的属性进行更改,由于ObjectAnimator已经自动实现了ValueAnimator.AnimatorUpdateListener,不再需要你来实现 ,这使得对一个对象添加动画变得简单了许多。
实例化一个ObjectAnimator类同上面很相似,但是你需要指定对象和该对象的属性的名称(一个字符串),该属性的值会在动画过程中发生变化,简单的示例如下:
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();
为了使得ObjectAnimator可以正确的更新属性,你必须做到以下几点
- 随着动画发生变化的对象属性必须有一个setter方法(骆驼命名规则)。因为ObjectAnimator动画自动更新属性时,它必须能够通过setter方法访问该属性。例如,如果属性名为foo,你需要有一个setfoo()方法。如果这个setter方法不存在,你有三个选择:
- 在对应的类中添加setter方法
- 使用一个封装类,封装类中定义一个setter方法,该方法可以将值传递给你想要改变的那个属性
- 使用ValueAnimator类来实现
- 如果在初始化时,你只指定了一个值,那么该值会被认为是动画的结束值。因此,在你的动画对象属性中必须有一个getter函数用于获取动画的起始值。例如,如果属性名为foo,你需要有一个getfoo()方法。
- 在ObjectAnimator中,属性的getter方法(如果有必要)和setter方法同你指定的的开始和结束值的数据类型必须相同。在下面的示例中,你的targetObject就必须有targetObject.setPropName(float) 和 targetObject.getPropName(float) 方法
ObjectAnimator.ofFloat(targetObject, "propName", 1f);
- 当你改变某些对象的某些属性时,你可能需要调用View的invalidate()方法通知屏幕使用更新的动画值来重绘。这种代码应该在onAnimationUpdate()的回调函数中调用。比如改变color属性后,只有调用屏幕重绘方法才会实现动画效果。所有的View类中已存在的setter方法,如setalpha()和settranslationx()会在方法内部刷新View,所以当你试图改变这些属性时,你并不需要重新调用invalidate()方法
如何使用AnimatorSet管理多个动画
在许多情况下,你想在另一个动画开始或者结束时执行一个动画,Android系统支持将多个动画同时放入一个AnimatorSet中,使得你可以指定这些动画是同时执行、按顺序执行或者一定延迟后执行。也可以在AnimatorSet中放入AnimatorSet。
下面的代码示例来自于 Bouncing Balls 示例中(已被改的简单了一些),AnimatorSet中包涵了以下的动画:
- 执行bounceAnim
- 同时执行squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2
- 执行bounceBackAnim
- 执行fadeAnim
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);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
如何实现动画事件监听
在动画执行的过程中,你可以监听一个动画的持续时间与下面的事件
- Animator.AnimatorListener
- onAnimationStart() - 当动画开始执行时被调用
- onAnimationEnd() - 当动画结束时被调用
- onAnimationRepeat() - 当动画重复时被调用
- onAnimationCancel() - 当动画被取消时被调用,无论动画如何结束的,同时也会调用onAnimationEnd()方法
- ValueAnimator.AnimatorUpdateListener
- onAnimationUpdate() - 动画的每一帧都会被调用. 监听这个接口,并使用计算得到的数值(即getAnimatedValue()方法)来修改你希望在当前动画中发生改变的对象的属性。
- 同ObjectAnimator一样,当你改变某些对象的某些属性时,你可能需要调用View的invalidate()方法通知屏幕使用更新的动画值来重绘。这种代码应该在onAnimationUpdate()的回调函数中调用。改变color属性后,只有调用屏幕重绘方法才会实现动画效果。所有的View类中已存在的setter方法,如setalpha()和settranslationx()会在方法内部刷新View,所以当你试图改变这些属性时,你并不需要重新调用invalidate()方法
如果你不想实现所有的animator.animatorlistener接口的方法。那么你可以选择重写AnimatorListenerAdapter类提供的空的实现方法。
下面是一个 Bouncing Balls 项目的示例,为了调用onAnimationEnd() 回调,创建了一个新的AnimatorListenerAdapter,代码如下
ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
如何实现ViewGroups的动画变化
属性动画对ViewGroup的内部成员改变的动画支持跟对View的动画支持一样出色
当一个ViewGroup内部的layout发生改变时,你可以使用LayoutTransition类对其添加动画支持。当你对ViewGroup内部的View调用setVisibility()方法时,View本身可以产生对应的消失或者显示的动画效果。当你添加或者移除View时,也有有对应的位移动画产生。你可以通过调用LayoutTransition的setanimator()方法对某个对象指定下面的某个动画常量:
- APPEARING - 在容器中的成员出现时的动画。
- CHANGE_APPEARING - 出现在容器的由于一个成员添加而引起的变化时的动画。
- DISAPPEARING - 在容器中的成员消失时的动画.
- CHANGE_DISAPPEARING - 出现在容器的由于一个成员消失而引起的变化时的动画。
你可以定义这四种类型的常量对应的动画效果,或者直接使用系统默认的效果
下面的LayoutAnimations示例展示了如何对一个布局文件设置一个系统默认的动画效果,使用起来十分的简单只需要设置android:animateLayoutchanges属性为true即可,示例如下
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />
设置这个属性为true,当有Views添加或被移除时,其内部的所有控件都会有动画效果的展示。