Android动画系列:
- 补间动画详解
- 帧动画
- LayoutAnimation
- LayoutTransition
- 属性动画 - 基本使用
- 属性动画 - Interpolator(内插器)
- 属性动画 - TypeEvaluator
- 属性动画 - Keyframe
- AnimatorSet
PropertyValuesHolder
PropertyValuesHolder是一个存储器,用来存储动画属性的信息和值,用于使用ValueAnimator或ObjectAnimator创建动画,它们对多个不同的属性并行操作。
valueAnimator
通过PropertyValuesHolder存储“translationX”和“translationY”属性的值。在AnimatorUpdateListener监听的onAnimationUpdate()中,ValueAnimator通过getAnimatedValue(String)方法获取相应动画属性的值,其参数为动画属性的信息,然后在调用相应的setXX(),设置view的属性,其自动调用invalidate()刷新屏幕。
PropertyValuesHolder holderRight = PropertyValuesHolder.ofFloat(PropertyConstant.PROPERTY_TRANSLATION_X,100f);
PropertyValuesHolder holderTop = PropertyValuesHolder.ofFloat(PropertyConstant.PROPERTY_TRANSLATION_Y, 300f);
ValueAnimator valueAnimator = ValueAnimator.ofPropertyValuesHolder(holderRight, holderTop);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setDuration(3000);
valueAnimator.setTarget(btnProperty);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float left = (float) valueAnimator.getAnimatedValue(PropertyConstant.PROPERTY_TRANSLATION_X);
float top = (float) valueAnimator.getAnimatedValue(PropertyConstant.PROPERTY_TRANSLATION_Y);
btnProperty.setTranslationX(left);
btnProperty.setTranslationY(top);
}
});
valueAnimator.start();
ObjectAnimator
鉴于ObjectAniator的局限性,PropertyValuesHolder内保存的属性,ObjectAniator
PropertyValuesHolder holderRight = PropertyValuesHolder.ofFloat(PropertyConstant.PROPERTY_TRANSLATION_X, 100f);
PropertyValuesHolder holderTop = PropertyValuesHolder.ofFloat(PropertyConstant.PROPERTY_TRANSLATION_Y, 300f);
ObjectAnimator objectAnimator = ObjectAnimator
.ofPropertyValuesHolder(btnProperty, holderRight, holderTop)
.setDuration(3000);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.start();
Keyframe
介绍
KeyFrame成为关键帧,是用来存储时间、值的键值对,实际上存储的是动画的执行进度和动画的属性值,用来定义动画的特定时间的帧。另外,每个关键帧可以拥有自己的插值器,用来控制动画在上一个关键帧和该关键帧的时间之间的间隔中的行为。
KeyFrame本事是一个抽象类。大家都知道的是抽象类本身并不能够实例化,如果想创建KeyFrame的实例,必须使用ofInt(),ofFloat()或ofObject()的工厂方法之一来获得相应类型的关键帧,而在工厂方法中创建的实例实际上是KeyFrame的子类。以ofInt为例:
public abstract class Keyframe implements Cloneable {
***
public static Keyframe ofInt(float fraction, int value) {
return new IntKeyframe(fraction, value);
}
***
static class IntKeyframe extends Keyframe {
***
IntKeyframe(float fraction, int value) {
mFraction = fraction;
mValue = value;
mValueType = int.class;
mHasValue = true;
}
IntKeyframe(float fraction) {
mFraction = fraction;
mValueType = int.class;
}
***
}
}
使用Keyframe.ofInt()工厂方法创建KeyFrame实例,实际上是在其方法内创建了IntKeyFrame的实例,而IntKeyFrame是不仅仅是KeyFrame的内部类,同时又是KeyFrame的子类,其内实现了KeyFrame的公共方法,作为工厂模式的产品类。因而调用ofInt()工厂方法可以创建KeyFrame实例。
常用API
- ofFloat(float fraction):创建KeyFrame实例
- ofFloat(float fraction, float value):创建KeyFrame实例
- ofInt(float fraction, int value):创建KeyFrame实例
- ofInt(float fraction):创建KeyFrame实例
- ofObject(float fraction, Object value):创建KeyFrame实例
- ofObject(float fraction):创建KeyFrame实例
- setInterpolator(TimeInterpolator interpolator):设置KeyFrame的插值器
注:
- 参数fraction为动画的执行进度百分比
- 参数value为该关键帧的动画属性值
使用步骤
- 采用ofInt(),ofFloat()或ofObject()的工厂方法等工厂方法创建KeyFrame实例
- 调用ofKeyframe()工厂方法来创建PropertyValuesHolder实例
- 通过PropertyValuesHolder实例创建ValueAnimatior实例
动画实例
有这么一个动画效果让Button旋转,在2.5s内从初始位置旋转360度,然后再反向旋转2.5s后回到初始位置。如果用Keyframe该如何处理呢?从动画效果上来看,有3个时间点0s、2.5s、5s,也就是动画应该有三个关键帧,其动画百分比分别说0f、0.5f、1f,动画属性分别说0f、360f、0f。既然分析出了关键帧,这件事事情就好办了。
示例代码及效果图如下:
// 1. 创建Keyframe实例
// 参数1为该关键帧处于动画的执行百分比
// 参数2为该关键字的动画属性值
Keyframe keyframe_0 = Keyframe.ofFloat(0f, 0f);
Keyframe keyframe_1 = Keyframe.ofFloat(0.5f, 360f);
Keyframe keyframe_2 = Keyframe.ofFloat(1f, 0f);
// 设置Keyframe的插值器
keyframe_1.setInterpolator(new LinearInterpolator());
keyframe_2.setInterpolator(new AccelerateDecelerateInterpolator());
// 2. 创建PropertyValuesHolder对象
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe(PropertyConstant.PROPERTY_ROTATION, keyframe_0, keyframe_1, keyframe_2);
// 3. 创建ValueAnimator实例
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(btnProperty, holder);
animator.setDuration(5000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start();