属性动画:ValueAnimator
前面了解的是视图动画,改变View的绘制,但那也只是表面上,其实View真正的属性都没有发生变化。从API 11开始Android引入了更强大的属性动画。
1、为什么引入属性动画?
之前学习的视图动画(补间动画:旋转、平移、放缩、透明度)只能在界面绘制上面做文章,也就是看到的是表面的“虚幻”画面,其实View的位置还在原来的地方。
举个例子,对View进行TranslateAnimation平移动画:
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 0,
Animation.RELATIVE_TO_SELF, 1.5f);
translateAnimation.setFillEnabled(true);
translateAnimation.setFillAfter(true);
translateAnimation.setDuration(1500);
mImageView.startAnimation(translateAnimation);

会发现点击最终View的位置并没有响应,反而点击原来的位置有点击事件,说明View真正的位置还是在原来的地方,不要被“表象”界面所欺骗。
另外传统的视图动画无法实现一些特殊的动效,于是从API 11开始引入了属性动画(Property Animation)。
2、属性动画(Property Animation)
“属性动画系统是一个强大的框架,可让您制作几乎所有内容的动画。您可以定义动画以随时间更改任何对象属性,而不管它是否绘制在屏幕上。属性动画会在指定的时间长度内更改属性(对象中的字段)的值。要制作动画,请指定要制作动画的对象属性,例如对象在屏幕上的位置,要制作动画的时间以及要在它们之间进行动画的值。”
2.1、官方介绍
通过属性动画系统,可以定义动画的以下特征:
- 持续时间:您可以指定动画的持续时间。默认长度为300毫秒。
- 时间插值:您可以指定如何根据动画的当前经过时间来计算属性的值。
- 重复次数和行为:您可以指定动画在持续时间结束时是否重复以及重复动画多少次。您还可以指定是否要使动画反向播放。设置为反向可先播放动画,然后反复播放动画,直到达到重复次数。
- 动画集:您可以将动画分组为逻辑集,这些逻辑集可以一起播放或按顺序播放,或在指定的延迟后播放。
- 帧刷新延迟:您可以指定刷新动画帧的频率。默认设置为每10毫秒刷新一次,但是应用程序刷新帧的速度最终取决于系统整体的繁忙程度以及系统为底层计时器提供服务的速度。
官方Github示例:android/animation-samples/tree/master/CustomTransition
2.2、属性动画和视图动画的区别
视图动画包括补间动画和帧动画,从API 1就有;属性动画从API 11才开始引入。
2.3、ValueAnimator和ObjectAnimator
属性动画有两种实现:ValueAnimator和ObjectAnimator。

3、Property Animator
说到属性动画必须要知道ValueAnimator和ObjectAnimator。本篇主要介绍ValueAnimator。
3.1、ValueAnimator
ValueAnimator类提供了一个简单的计时引擎,用于运行动画,该动画计算动画值并将其设置在目标对象上。有如下6种方式构造ValueAnimator:
①new ValueAnimator():直接用默认构造函数,不过需要继续设置属性动画。
②ValueAnimator.ofInt(int... values):构造并返回一个在int值之间进行动画处理的ValueAnimator
③ValueAnimator.ofFloat(float... values):构造并返回一个在浮动值之间进行动画处理的ValueAnimator。
④ValueAnimator.ofArgb(int... values):构造并返回一个在颜色值之间进行动画处理的ValueAnimator
⑤ValueAnimator.ofObject(TypeEvaluator evaluator, Object... values):构造并返回一个在对象值之间进行动画处理的ValueAnimator。 单个值表示该值是要动画显示的值。 但是,这在ValueAnimator对象中通常没有用,因为该对象无法确定动画的起始值(与ObjectAnimator不同,后者可以从正在动画的目标对象和属性中获取该值)。 因此,通常应该有两个或多个值。ObjectAnimator也有类似的方法,详见《属性动画:ObjectAnimator基础》。
⑥ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder... values):构造并返回一个ValueAnimator,该动画在PropertyValuesHolder对象中指定的值之间进行动画处理。
3.2、ObjectAnimator
ObjectAnimator的子类提供对目标对象的动画设置的支持。此类的构造函数使用参数来定义将被动画处理的目标对象以及将被动画处理的属性的名称。然后在内部确定适当的set/get函数,动画将根据需要调用这些函数来设置属性动画。关于ObjectAnimator详见《属性动画:ObjectAnimator基础》。
3.3、AnimatorListener
在Animator类中定义了AnimatorListener接收动画通知。通知指示与动画相关的事件,例如动画的结束或重复。视图动画Animation也有监听器AnimationListener,详见《视图动画:Animation》。
/**
* 从动画接收通知。通知指示与动画相关的事件,例如动画的结束或重复。
*/
public static interface AnimatorListener {
default void onAnimationStart(Animator animation, boolean isReverse) {
onAnimationStart(animation);
}
default void onAnimationEnd(Animator animation, boolean isReverse) {
onAnimationEnd(animation);
}
/**
* 通知动画的开始。
*/
void onAnimationStart(Animator animation);
/**
* 通知动画结束。 对于重复计数设置为INFINITE的动画,不会调用此回调。
*/
void onAnimationEnd(Animator animation);
/**
* 通知取消动画。 对于重复计数设置为INFINITE的动画,不会调用此回调。
*/
void onAnimationCancel(Animator animation);
/**
* 通知动画重复
*/
void onAnimationRepeat(Animator animation);
}
添加AnimatorListener属性动画监听器,需要先实现接口中的四个方法。
animator.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) {
}
});
调用Animator类中的addListener(AnimatorListener listener)方法
/**
* Adds a listener to the set of listeners that are sent events through the life of an
* animation, such as start, repeat, and end.
*
* @param listener the listener to be added to the current set of listeners for this animation.
*/
public void addListener(AnimatorListener listener) {
if (mListeners == null) {
mListeners = new ArrayList<AnimatorListener>();
}
mListeners.add(listener);
}
或者removeListener(AnimatorListener listener)方法移除属性动画监听器。
/**
* Removes a listener from the set listening to this animation.
*
* @param listener the listener to be removed from the current set of listeners for this
* animation.
*/
public void removeListener(AnimatorListener listener) {
if (mListeners == null) {
return;
}
mListeners.remove(listener);
if (mListeners.size() == 0) {
mListeners = null;
}
}
3.4、AnimatorListenerAdapter
在android.animation包中有一个抽象类AnimatorListenerAdapter,实现了Animator.AnimatorListener和Animator.AnimatorPauseListener监听器接口,里面都是空方法,这样避免开发者每次添加监听器都要实现所有的接口,只需选择重写需要的空方法即可。
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
Animator.AnimatorPauseListener {
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationPause(Animator animation) {
}
@Override
public void onAnimationResume(Animator animation) {
}
}
4、ValueAnimator
先简单介绍一下ValueAnimator Animator的简单使用方法,更高级的操作后面继续深入学习。
4.1、构造函数
直接调用ValueAnimator构造方法创建实例。
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setIntValues(0, 100);
valueAnimator.setDuration(1500);
valueAnimator.setInterpolator(new OvershootInterpolator(1.0f));
valueAnimator.setRepeatCount(1);
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
4.2、通过of方法获取ValueAnimator实例
①ValueAnimator.ofArgb(int... values):关于颜色详见《Color详解》。
ValueAnimator colorAnimator = ValueAnimator.ofArgb(Color.parseColor("#f7acbc"), Color.parseColor("#003a6c"));
colorAnimator.setDuration(3000);
colorAnimator.setRepeatCount(ValueAnimator.INFINITE);
colorAnimator.setRepeatCount(ValueAnimator.REVERSE);
colorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (Integer) animation.getAnimatedValue();
}
});
colorAnimator.start();

②ValueAnimator.ofInt(int... values):可以用这个值设置View的位置、旋转等。
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 400);
valueAnimator.setDuration(2000);
valueAnimator.setInterpolator(new OvershootInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
}
});

③ofObject:该方法效果比较强大。另外通过ObjectAnimator的ofObject传入对应的属性名也能达到类似的效果。
ValueAnimator valueAnimator = ValueAnimator.ofObject(new CharEvaluator(), 'A', 'Z');
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Character character = (Character) animation.getAnimatedValue();
textView.setText(String.valueOf(character));
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(2000);
valueAnimator.start();

之所以能够实现上面的效果,得益于自定义的TypeEvaluator,关于自定义TypeEvaluator详见《属性动画:TypeEvaluator》。
public class CharEvaluator implements TypeEvaluator<Character> {
@Override
public Character evaluate(float fraction, Character startValue, Character endValue) {
int startInt = (int) startValue;
int curInt = (int) (startInt + fraction * (endValue - startValue));
return (char) curInt;
}
}
4.3、AnimatorUpdateListener
ValueAnimator类中增加了AnimatorUpdateListener监听器接口,在onAnimationUpdate(ValueAnimator animation)回调方法中获取实时计算变化的值,设置给View。
后面需要学习的ObjectAnimator不需要设置任何AnimatorUpdateListener,只需设置要改变的属性名,动画值的过程中会自动反射调用对应属性的setter方法,进行设置。详见《属性动画:ObjectAnimator基础》。
/**
* Implementors of this interface can add themselves as update listeners
* to an <code>ValueAnimator</code> instance to receive callbacks on every animation
* frame, after the current frame's values have been calculated for that
* <code>ValueAnimator</code>.
*/
public static interface AnimatorUpdateListener {
/**
* <p>Notifies the occurrence of another frame of the animation.</p>
*
* @param animation The animation which was repeated.
*/
void onAnimationUpdate(ValueAnimator animation);
}
给属性动画添加AnimatorUpdateListener监听器,源码可以发现,可以添加很多个监听器,存入到集合中。
/**
* Adds a listener to the set of listeners that are sent update events through the life of
* an animation. This method is called on all listeners for every frame of the animation,
* after the values for the animation have been calculated.
*
* @param listener the listener to be added to the current set of listeners for this animation.
*/
public void addUpdateListener(AnimatorUpdateListener listener) {
if (mUpdateListeners == null) {
mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
}
mUpdateListeners.add(listener);
}
移除某个监听器
/**
* Removes a listener from the set listening to frame updates for this animation.
*
* @param listener the listener to be removed from the current set of update listeners
* for this animation.
*/
public void removeUpdateListener(AnimatorUpdateListener listener) {
if (mUpdateListeners == null) {
return;
}
mUpdateListeners.remove(listener);
if (mUpdateListeners.size() == 0) {
mUpdateListeners = null;
}
}
移除属性动画中所有的监听器
/**
* Removes all listeners from the set listening to frame updates for this animation.
*/
public void removeAllUpdateListeners() {
if (mUpdateListeners == null) {
return;
}
mUpdateListeners.clear();
mUpdateListeners = null;
}
4.4、其它方法
①areAnimatorsEnabled():返回当前是否在系统范围内启用动画制作器。 默认情况下,所有动画师均处于启用状态。
②clone():克隆一个完全一样的ValueAnimator实例,所有设置和监听器。
③setStartDelay(long startDelay):调用start()之后延迟动画启动的时间(以ms为单位)。 请注意,启动延迟应始终为非负值。 N或以上的任何负启动延迟都将重置为0。
到这里也只是了解了关于属性动画ValueAnimator的一些皮毛,继续学习另一个属性动画相关的技术ObjectAnimator。
参考资料:
Android Developers > Docs > Reference > ValueAnimator
Property Animation developer guide
属性动画ValueAnimator用法
ValueAnimator的简单介绍和使用
ValueAnimator详解
How property animation works
属性动画 ValueAnimator 运行原理全解析