如果想根据某个属性TYPE来实现动画,但是这个Type又不是Android系统内置的,这个时候就需要创建一个自己的evaluator来实现了,并且新创建的type必须实现接口TypeEvaluator。Android系统内置的type有int,float和color,他们对应的evaluator是IntEvaluator、FloatEvaluator和ArgbEvaluator。接口TypeEvaluator内只有一个方法,用来计算要实现动画属性的值。
/** * Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators * allow developers to create animations on arbitrary property types, by allowing them to supply * custom evaluators for types that are not automatically understood and used by the animation * system. * * @see ValueAnimator#setEvaluator(TypeEvaluator) */ public interface TypeEvaluator<T> { /** * This function returns the result of linearly interpolating the start and end values, with * <code>fraction</code> representing the proportion between the start and end values. The * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. * * @param fraction The fraction from the starting to the ending values * @param startValue The start value. * @param endValue The end value. * @return A linear interpolation between the start and end values, given the * <code>fraction</code> parameter. */ public T evaluate(float fraction, T startValue, T endValue); }
先看看Android系统内置FloatEvaluator是怎么弄的:
public class FloatEvaluator implements TypeEvaluator<Number> { /** * This function returns the result of linearly interpolating the start and end values, with * <code>fraction</code> representing the proportion between the start and end values. The * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. * * @param fraction The fraction from the starting to the ending values * @param startValue The start value; should be of type <code>float</code> or * <code>Float</code> * @param endValue The end value; should be of type <code>float</code> or <code>Float</code> * @return A linear interpolation between the start and end values, given the * <code>fraction</code> parameter. */ public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); } }
还是举个例子来测试一下,先看下面图中的效果:
这个动画在Android-Property Animation(属性动画)中就实现过了,当时是这么实现的:
private void startValueAnimation(){ if(mValueAnimator == null){ mValueAnimator = ValueAnimator.ofFloat(0, 500); } mValueAnimator.setInterpolator(new AnticipateInterpolator()); mValueAnimator.setTarget(mImageView); mValueAnimator.setDuration(3000); mValueAnimator.setRepeatCount(1); mValueAnimator.start(); mValueAnimator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //同时设置X,Y 两个属性 mImageView.setTranslationX((Float) animation.getAnimatedValue()); mImageView.setTranslationY((Float) animation.getAnimatedValue()); } }); }
在动画update的时候同时更新View的X和Y属性。此外, 使用AnimatorSet也可以实现这种动画效果。除了这两种之外还有没有呢?就是自定义一个TypeEvaluator,主要代码如下:
private void startObjectAnimation() { ViewXYHolder viewXYHolder = new ViewXYHolder(mImageView); XYHolder startXY = new XYHolder(0f, 0f); XYHolder endXY = new XYHolder(500f, 500f); ObjectAnimator objectAnimator = ObjectAnimator.ofObject(viewXYHolder, "xY", new XYmEvaluator(), startXY, endXY); objectAnimator.setInterpolator(new LinearInterpolator()); objectAnimator.setDuration(3000); objectAnimator.start(); } public class XYmEvaluator implements TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue) { XYHolder startXY = (XYHolder) startValue; XYHolder endXY = (XYHolder) endValue; return new XYHolder(startXY.getX() + fraction * (endXY.getX() - startXY.getX()), startXY.getY() + fraction * (endXY.getY() - startXY.getY())); } } public class XYHolder{ private float mX; private float mY; public XYHolder(float x, float y) { mX = x; mY = y; } public float getX() { return mX; } public void setX(float x) { mX = x; } public float getY() { return mY; } public void setY(float y) { mY = y; } } public class ViewXYHolder{ private View imageView; public ViewXYHolder(View view){ imageView = view; } //看到这个是不是感觉跟第一种方法一样的感脚,只是封装的不同 public void setXY(XYHolder xyHolder) { imageView.setX(xyHolder.getX()); imageView.setY(xyHolder.getY()); } public XYHolder getXY() { return new XYHolder(imageView.getX(), imageView.getY()); } }
而其实,对于这个例子,使用的对象是一个View,Android系统中有封装View属性动画的一个类: ViewPropertyAnimator,其简单使用方式如下:
private void startViewPropertyAnimation(){ ViewPropertyAnimator viewPropertyAnimator; viewPropertyAnimator = mImageView.animate().x(500).y(500); viewPropertyAnimator.setDuration(3000); viewPropertyAnimator.start(); }
同样也能实现上面的动画效果,只是只局限于View,不管方法怎么变,但是最终原理都是一样的,都是要同时改变X 和 Y两个属性的值。复杂一点的例子还是直接参考ApiDemo比较好,ApiDemo里面有个Custom Evaluator,值得学习!