本周做一个动画的时候用到了ObjectAnimator,动画要求,一个柱状图根据数值的不同慢慢升起,但是使用了ObjectAnimator类的时候,发现该类并不能满足我的需求,后来使用了它的父类ValueAnimator,十分简单的解决了这个问题。
首先介绍下ObjectAnimator:
public final class ObjectAnimator extends ValueAnimator
ObjectAnimator内部实现的比较常用的方法有:
我们可以采用以下这种形式进行运用(比如旋转动画):
ObjectAnimatoranimator = ObjectAnimator.ofFloat(tv,"rotation",0,180,0);
animator.setDuration(2000);
animator.start();
首先看ObjectAnimator.ofFloat()和ObjectAnimator.ofInt()这两个方法:
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setFloatValues(values); return anim; }
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setIntValues(values); return anim; }
简单的理解是两者方法的参数表第一个都是一个对象,也就是我们设置动画的view,第二个是代表动画的String ,比如”alpha”, “rotation”等等,第三个是一个参数序列,内部都实现了一个ObjectAnimator的实例,但是ofFloat设置的是浮点型数据, ofInt设置的时候整型数据,两者都返回了一个ObjectAnimator的实例。
那么构造方法实现的是什么呢?
private ObjectAnimator(Object target, String propertyName) { setTarget(target); setPropertyName(propertyName); }
setTarget()方法:顾名思义就是设置当前属性动画的对象,对于对象产生了一个弱引用,便于修改对象的属性。
@Override public void setTarget(@Nullable Object target) { final Object oldTarget = getTarget(); if (oldTarget != target) { if (isStarted()) { cancel(); } mTarget = target == null ? null : new WeakReference<Object>(target); // New target should cause re-initialization prior to starting mInitialized = false; } }
setPropertyName()方法,利用字符串对象propertyName设置对应的动画
View中也没有rotation这个属性。那它是怎么来改变这个值的呢?其实,ObjectAnimator做动画,并不是根据控件xml中的属性来改变的,而是通过指定属性所对应的set方法来改变的。比如,我们指定的改变rotation的属性值,ObjectAnimator在做动画时就会到指定控件(TextView)中去找对应的setRotation()方法来改变控件中对应的值。同样的道理,当我们在最开始的示例代码中,指定改变”alpha”属性值的时候,ObjectAnimator也会到TextView中去找对应的setAlpha()方法。那TextView中都有这些方法吗,有的,这些方法都是从View中继承过来的,在View中有关动画,总共有下面几组set方法:
//1、透明度:alpha
publicvoidsetAlpha(floatalpha)
//2、旋转度数:rotation、rotationX、rotationY
publicvoidsetRotation(floatrotation)
publicvoidsetRotationX(floatrotationX)
publicvoidsetRotationY(floatrotationY)
//3、平移:translationX、translationY
publicvoidsetTranslationX(floattranslationX)
publicvoidsetTranslationY(floattranslationY)
//缩放:scaleX、scaleY
publicvoidsetScaleX(floatscaleX)
publicvoidsetScaleY(floatscaleY)
可以看到在View中已经实现了有关alpha,rotaion,translate,scale相关的set方法。所以我们在构造ObjectAnimator时可以直接使用。
在开始逐个看这些函数的使用方法前,我们先做一个总结:
1、要使用ObjectAnimator来构造对画,要操作的控件中,必须存在对应的属性的set方法
2、setter 方法的命名必须以骆驼拼写法命名,即set后每个单词首字母大写,其余字母小写,即类似于setPropertyName所对应的属性为propertyName
ObjectAnimator的动画的实现原理
ValueAnimator的动画流程与ObjectAnimator的动画流程做了个对比。
可以看到ObjectAnimator的动画流程中,也是首先通过加速器产生当前进度的百分比,然后再经过Evaluator生成对应百分比所对应的数字值。这两步与ValueAnimator是完全一样的,唯一不同的是最后一步,在ValueAnimator中,我们要通过添加监听器来监听当前数字值。而在ObjectAnimator中,则是先根据属性值拼装成对应的set函数的名字,比如这里的scaleY的拼装方法就是将属性的第一个字母强制大写后,与set拼接,所以就是setScaleY。然后通过反射找到对应控件的setScaleY(float scaleY)函数,将当前数字值做为setScaleY(floatscale)的参数将其传入。
这里在找到控件的set函数以后,是通过反射来调用这个函数的,有关反射的使用大家可以参考《夯实JAVA基本之二——反射(1):基本类周边信息获取》
这就是ObjectAnimator的流程,最后一步总结起来就是调用对应属性的set方法,将动画当前数字值做为参数传进去。
下面是几个常用的函数
** * 设置动画时长,单位是毫秒 */ ValueAnimator setDuration(long duration) /** * 获取ValueAnimator在运动时,当前运动点的值 */ Object getAnimatedValue(); /** * 开始动画 */ void start() /** * 设置循环次数,设置为INFINITE表示无限循环 */ void setRepeatCount(int value) /** * 设置循环模式 * value取值有RESTART,REVERSE, */ void setRepeatMode(int value) /** * 取消动画 */ void cancel() |
(2)、监听器相关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** * 监听器一:监听动画变化时的实时值 */ public static interface AnimatorUpdateListener { void onAnimationUpdate(ValueAnimator animation); } //添加方法为:public void addUpdateListener(AnimatorUpdateListener listener) /** * 监听器二:监听动画变化时四个状态 */ public static interface AnimatorListener { void onAnimationStart(Animator animation); void onAnimationEnd(Animator animation); void onAnimationCancel(Animator animation); void onAnimationRepeat(Animator animation); } //添加方法为:public void addListener(AnimatorListener listener) |
(3)、插值器与Evaluator
1 2 3 4 5 6 7 8 | /** * 设置插值器 */ public void setInterpolator(TimeInterpolator value) /** * 设置Evaluator */ public void setEvaluator(TypeEvaluator value) |
而ValusAnimator的用法,如下图
private void performAnimate(final Viewtarget, final int start, final int end) {
ValueAnimator valueAnimator =ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(newValueAnimator.AnimatorUpdateListener() {
//持有一个IntEvaluator对象,方便下面估值的时候使用
private IntEvaluator mEvaluator =new IntEvaluator();
@Override
public voidonAnimationUpdate(ValueAnimator animator) {
//获得当前动画的进度值,整型,1-100之间
int currentValue = (Integer)animator.getAnimatedValue();
//计算当前进度占整个动画过程的比例,浮点型,0-1之间
float fraction = currentValue /100f;
//这里我偷懒了,不过有现成的干吗不用呢
//直接调用整型估值器通过比例计算出宽度,然后再设给Button
target.getLayoutParams().height= mEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
}
也就是说ValueAnimator实际上并不对对象进行修改,只是计算了一系列的数值,我们需要自己对ValueAnimator设置监听器进行回调,并在其中设置对象的属性,达到动画的效果。