21.源码阅读(属性动画ValueAnimator-api26)

通常用ValueAnimator实现动画的过渡效果,代码如下

ValueAnimator valueAnimator = ValueAnimator.ofFloat(1, 100);  
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {  
       @Override  
       public void onAnimationUpdate(ValueAnimator animator) {  
            //获得当前动画的进度值,整型,1-100之间  
           int currentValue = (Integer)animator.getAnimatedValue();  

       }  
});  
valueAnimator.setDuration(450).start();  

源码提供的创建ValueAnimator对象的方法有三个
ofArgb:接收颜色值作为参数,实现色值过渡的效果
ofFloat:接收float类型的参数
ofInt:接收int类型参数

这三个方法对应了不同的应用场景,原理是相同的,今天就以ofFloat方法为例做说明。可以看到这个方法只是创建了一个ValueAnimator对象,将values传递到构造方法中并返回了这个对象

ofFloat

    /**
     * 从下面的注释可以看出,ValueAnimator和ObjectAnimator有所不同,ValueAnimator典型  
     * 的方式就是接收两个参数,一个作为起始值,一个作为结束值,而ObjectAnimator是可以
     * 传递一个参数作为结束值的,但是一个参数下ValueAnimator无法界定动画开始的值
     * Constructs and returns a ValueAnimator that animates between float values. A single
     * value implies that that value is the one being animated to. However, this is not typically
     * useful in a ValueAnimator object because there is no way for the object to determine the
     * starting value for the animation (unlike ObjectAnimator, which can derive that value
     * from the target object and property being animated). Therefore, there should typically
     * be two or more values.
     *
     * @param values A set of values that the animation will animate between over time.
     * @return A ValueAnimator object that is set up to animate between the given values.
     */
    public static ValueAnimator ofFloat(float... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setFloatValues(values);
        return anim;
    }

构造方法是空的,所以我们来看setFloatValues方法

    /**
     * <p>If there are already multiple sets of values defined for this ValueAnimator via more
     * than one PropertyValuesHolder object, this method will set the values for the first
     * of those objects.</p>
     *
     * @param values A set of values that the animation will animate between over time.
     */
    public void setFloatValues(float... values) {
        if (values == null || values.length == 0) {
            return;
        }
        //mValues 是PropertyValuesHolder[]数组对象,这样判断的目的是看是否setFloatValues 
        //已经被调用过,如果有则已经存在这个值,此时就像注释所说,将values放在第一个位
        //置,第一次肯定是null,所以先走setValues方法
        if (mValues == null || mValues.length == 0) {
            setValues(PropertyValuesHolder.ofFloat("", values));
        } else {
            PropertyValuesHolder valuesHolder = mValues[0];
            valuesHolder.setFloatValues(values);
        }
        // New property/values/target should cause re-initialization prior to starting
        mInitialized = false;
    }

setValus方法分两步走,第一步是先将values包装成一个PropertyValuesHolder对象,PropertyValuesHolder是父类指向子类对象,ofFloat方法调用则返回的实际是FloatPropertyValuesHolder对象,它还有其他子类,比如IntPropertyValuesHolder,MultiFloatValuesHolder

PropertyValuesHolder.ofFloat("", values)

   /**
     * Constructs and returns a PropertyValuesHolder with a given property name and
     * set of float values.
     * @param propertyName The name of the property being animated.
     * @param values The values that the named property will animate between.
     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
     */
    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
        return new FloatPropertyValuesHolder(propertyName, values);
    }

到了FloatPropertyValuesHolder构造方法中,可以看到两个参数的走向开始分开,一个传递给了父类的构造中,一个调用setFloatValues方法

public FloatPropertyValuesHolder(String propertyName, float... values) {
        super(propertyName);
        setFloatValues(values);
}

propertyName在父类中被保存了起来,因为我们看的是ValueAnimator的源码,所以实际上这个参数没有用,它也是个空值

private PropertyValuesHolder(String propertyName) {
        mPropertyName = propertyName;
}

重点来看setFloatValues方法

@Override
public void setFloatValues(float... values) {
       super.setFloatValues(values);
       mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
}

先通过super来到父类的方法中

    /**
     * Set the animated values for this object to this set of floats.
     * If there is only one value, it is assumed to be the end value of an animation,
     * and an initial value will be derived, if possible, by calling a getter function
     * on the object. Also, if any value is null, the value will be filled in when the animation
     * starts in the same way. This mechanism of automatically getting null values only works
     * if the PropertyValuesHolder object is used in conjunction
     * {@link ObjectAnimator}, and with a getter function
     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
     * no way of determining what the value should be.
     *
     * @param values One or more values that the animation will animate between.
     */
    public void setFloatValues(float... values) {
        //float的Class类型
        mValueType = float.class;
        mKeyframes = KeyframeSet.ofFloat(values);
    }

可以看出,这个方法就是为了将KeyFrame对象封装成FloatKeyframeSet返回,关键的代码在于KeyFrame中的ofFloat方法做了什么

public static KeyframeSet ofFloat(float... values) {
        boolean badValue = false;
        //计算可变参数的长度
        int numKeyframes = values.length;
        //创建出一个长度大于等于2的FloatKeyframe数组
        FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
        //如果之传入了一个值
        if (numKeyframes == 1) {
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
            keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
            //返回 a!=a,isNaN这个方法就是判断values[0]是不是不是数字,返回true,表示不是
            //数字,那么badValue=true,表示是坏值
            if (Float.isNaN(values[0])) {
                badValue = true;
            }
        //如果可变参数length大于1
        } else {
            //这里假设numKeyframes是3,那么
            //keyframes[0]  = Keyframe.ofFloat(0f, values[0]);
            //keyframes[1]  = Keyframe.ofFloat(0.5f,value[1]);
            //keyframes[2]  = Keyframe.ofFloat(1f,values[2]); 
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
            for (int i = 1; i < numKeyframes; ++i) {
                keyframes[i] =
                        (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
                if (Float.isNaN(values[i])) {
                    badValue = true;
                }
            }
        }
        if (badValue) {
            Log.w("Animator", "Bad value (NaN) in float animator");
        }
        return new FloatKeyframeSet(keyframes);
    }

看看Keyframe.ofFloat,传入的第一个参数可以看作时间,这个时间是在总时间所占的比例,从0到1,第二个参数是在这个时间比例上所对应的值,这个值将是实际所展示出的值,如果是色值就是当前时间点位置对应的颜色值,如果是距离,那就是当前时间点位所在的位置

    /**
     * Constructs a Keyframe object with the given time and value. The time defines the
     * time, as a proportion of an overall animation's duration, at which the value will hold true
     * for the animation. The value for the animation between keyframes will be calculated as
     * an interpolation between the values at those keyframes.
     *
     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
     * of time elapsed of the overall animation duration.
     * @param value The value that the object will animate to as the animation time approaches
     * the time in this keyframe, and the the value animated from as the time passes the time in
     * this keyframe.
     */
    public static Keyframe ofFloat(float fraction, float value) {
        //封装成FloatKeyframe对象,同样FloatKeyframe也是个父类指向子类对象,他也有其他
        //子类,像IntKeyframe等
        return new FloatKeyframe(fraction, value);
    }

在这个构造方法中保存了传入的参数,将这些参数封装成了FloatKeyframe对象,那么也就是说,ValueAnimator的ofFloat方法传入几个可变参数,最终就会创建几个FloatKeyframe对象

FloatKeyframe(float fraction, float value) {
            mFraction = fraction;
            mValue = value;
            mValueType = float.class;
            mHasValue = true;
        }

到了这里PropertyValuesHolder中的方法setFloatValues中的super.setFloatValues(values);执行完成,它的作用就是将可变参数values解析成了Keyframes,Keyframes是父类,真正的子类是FloatKeyframeSet,FloatKeyframeSet 继承 KeyframeSet ,KeyframeSet又继承Keyframes。成员变量mKeyframes中保存了FloatKeyframe对象的数组,每个对象封装了每个临界点的fraction比例和value值

然后将这个mKeyframes进行了转换,保存在FloatPropertyValuesHolder的成员变量Keyframes.FloatKeyframes mFloatKeyframes中

@Override
public void setFloatValues(float... values) {
    super.setFloatValues(values);
    mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
 }

到此为止PropertyValuesHolder.ofFloat("", values)方法执行完成,他的作用就是创建了FloatPropertyValuesHolder对象,并将可变参数values封装保存到了成员变量mFloatKeyframes中

然后就要开始执行setValues(PropertyValuesHolder.ofFloat("", values))方法了,这里是将PropertyValuesHolder保存在了一个map中

    /**
     * Sets the values, per property, being animated between. This function is called internally
     * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can
     * be constructed without values and this method can be called to set the values manually
     * instead.
     *
     * @param values The set of values, per property, being animated between.
     */
    public void setValues(PropertyValuesHolder... values) {
        int numValues = values.length;
        mValues = values;
        mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
        for (int i = 0; i < numValues; ++i) {
            PropertyValuesHolder valuesHolder = values[i];
            //以属性名为key,但其实因为是valueAnimator,所以key是空字符串
            mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
        }
        // New property/values/target should cause re-initialization prior to starting
        mInitialized = false;
    }

这时第一次调用ValueAnimator中setFloatValues后的逻辑,那么如果用户获取到ValueAnimator对象之后,在次通过其对象调用setFloatValues会怎样呢?此时就会走到下边的逻辑中

public void setFloatValues(float... values) {
        if (values == null || values.length == 0) {
            return;
        }
        if (mValues == null || mValues.length == 0) {
            setValues(PropertyValuesHolder.ofFloat("", values));
        } else {
            //如果mValues已经存在了,说明有过调用,此时就取出PropertyValuesHolder[] mValues
            //数组中的第一个PropertyValuesHolder 对象,通过调用它的setFloatValues方法
            //更新其成员变量mKeyframes的值
            PropertyValuesHolder valuesHolder = mValues[0];
            valuesHolder.setFloatValues(values);
        }
        // New property/values/target should cause re-initialization prior to starting
        mInitialized = false;
    }

setValues方法结束了,也可以说是ValueAnimator的ofFloat方法也结束了,对于ValueAnimator来说,调用ofFloat的逻辑简单总结一下做了哪些事情
第一,将values可变参数数组封装成FloatPropertyValuesHolder对象,对象中的变量Keyframes.FloatKeyframes mFloatKeyframes保存了fraction和value的数据
第二,将这个FloatPropertyValuesHolder放入HashMap集合,以propertyName为key值存放

setDuration

保存动画执行的时间mDuration

    /**
     * Sets the length of the animation. The default duration is 300 milliseconds.
     *
     * @param duration The length of the animation, in milliseconds. This value cannot
     * be negative.
     * @return ValueAnimator The object called with setDuration(). This return
     * value makes it easier to compose statements together that construct and then set the
     * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
     */
    @Override
    public ValueAnimator setDuration(long duration) {
        if (duration < 0) {
            throw new IllegalArgumentException("Animators cannot have negative duration: " +
                    duration);
        }
        mDuration = duration;
        return this;
    }

addUpdateListener

将监听器存入集合,也就是可以添加大于一个的listener

    /**
     * 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);
    }

start

start方法是最关键的方法

    @Override
    public void start() {
        start(false);
    }
    /**
     * Start the animation playing. This version of start() takes a boolean flag that indicates
     * whether the animation should play in reverse. The flag is usually false, but may be set
     * to true if called from the reverse() method.
     *
     * <p>The animation started by calling this method will be run on the thread that called
     * this method. This thread should have a Looper on it (a runtime exception will be thrown if
     * this is not the case). Also, if the animation will animate
     * properties of objects in the view hierarchy, then the calling thread should be the UI
     * thread for that view hierarchy.</p>
     *
     * @param playBackwards Whether the ValueAnimator should start playing in reverse.
     */
    private void start(boolean playBackwards) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        //playBackwards表示是否倒序执行,一般否是false,除非你有特殊需求这样设置
        //mSuppressSelfPulseRequested,这个值通过方法startWithoutPulsing设置,就把他默认当作false即可
        mReversing = playBackwards;
        mSelfPulse = !mSuppressSelfPulseRequested;
        // Special case: reversing from seek-to-0 should act as if not seeked at all.
        //倒序的逻辑
        if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
            if (mRepeatCount == INFINITE) {
                // Calculate the fraction of the current iteration.
                float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
                mSeekFraction = 1 - fraction;
            } else {
                mSeekFraction = 1 + mRepeatCount - mSeekFraction;
            }
        }
        mStarted = true;
        mPaused = false;
        mRunning = false;
        mAnimationEndRequested = false;
        // Resets mLastFrameTime when start() is called, so that if the animation was running,
        // calling start() would put the animation in the
        // started-but-not-yet-reached-the-first-frame phase.
        mLastFrameTime = -1;
        mFirstFrameTime = -1;
        mStartTime = -1;
        addAnimationCallback(0);
        //mStartDelay 是延迟播放动画的时间,通过调用setStartDelay设置,表示延迟多久可以
        //执行动画,默认不延迟为0
        if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
            // If there's no start delay, init the animation and notify start listeners right away
            // to be consistent with the previous behavior. Otherwise, postpone this until the first
            // frame after the start delay.
            startAnimation();
            if (mSeekFraction == -1) {
                // No seek, start at play time 0. Note that the reason we are not using fraction 0
                // is because for animations with 0 duration, we want to be consistent with pre-N
                // behavior: skip to the final value immediately.
                setCurrentPlayTime(0);
            } else {
                setCurrentFraction(mSeekFraction);
            }
        }
    }

startAnimation

    /**
     * Called internally to start an animation by adding it to the active animations list. Must be
     * called on the UI thread.
     */
    private void startAnimation() {
        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
            Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                    System.identityHashCode(this));
        }

        mAnimationEndRequested = false;
        initAnimation();
        mRunning = true;
        if (mSeekFraction >= 0) {
            mOverallFraction = mSeekFraction;
        } else {
            mOverallFraction = 0f;
        }
        //这个mListeners 指的是addListener添加的回调,包括onAnimationStart 
        //onAnimationEnd onAnimationCancel  onAnimationRepeat
        if (mListeners != null) {
            notifyStartListeners();
        }
    }

initAnimation

     /**
     * This function is called immediately before processing the first animation
     * frame of an animation. If there is a nonzero <code>startDelay</code>, the
     * function is called after that delay ends.
     * It takes care of the final initialization steps for the
     * animation.
     *
     *  <p>Overrides of this method should call the superclass method to ensure
     *  that internal mechanisms for the animation are set up correctly.</p>
     */
    //如果你的API允许使用者重写你的方法,但是呢,你又需要你自己的方法(父方法)在重写的
    //时候也被调用,这时候你可以使用@CallSuper标注,当重写的方法没有调用父方法时,工
    //具就会给予标记提示
    @CallSuper
    void initAnimation() {
        if (!mInitialized) {
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                //每个PropertyValuesHolder的init方法都被调用
                mValues[i].init();
            }
            mInitialized = true;
        }
    }

来到PropertyValuesHolder中的init方法

    /**
     * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used
     * to calculate animated values.
     */
    void init() {
        if (mEvaluator == null) {
            // We already handle int and float automatically, but not their Object
            // equivalents
            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
                    (mValueType == Float.class) ? sFloatEvaluator :
                    null;
        }
        if (mEvaluator != null) {
            // KeyframeSet knows how to evaluate the common types - only give it a custom
            // evaluator if one has been set on this class
            //我们已经知道Keyframes是一个接口,所以这里又要去它的实现类中看setEvaluator 
            //方法-----FloatKeyframeSet        
            mKeyframes.setEvaluator(mEvaluator);
        }
    }

FloatKeyframeSet --> KeyframeSet --> Keyframes 三者的继承实现关系
来到FloatKeyframeSet中发现没有setEvaluator方法,那么再来到KeyframeSet 中,可以看到这里仅仅是保存了Evaluator,并没有做别的,那么动画的逻辑在哪,再回过头看一看

    /**
     * Sets the TypeEvaluator to be used when calculating animated values. This object
     * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
     * both of which assume their own evaluator to speed up calculations with those primitive
     * types.
     *
     * @param evaluator The TypeEvaluator to be used to calculate animated values.
     */
    public void setEvaluator(TypeEvaluator evaluator) {
        mEvaluator = evaluator;
    }

回来再看看这一段代码,你会发现注释的第一句话这样说到,这个功能是再动画开始前执行的,也就是这只是个初始化的动作,给每一个PropertyValuesHolder中的mKeyframes设置Evaluator

    /**
     * This function is called immediately before processing the first animation
     * frame of an animation. If there is a nonzero <code>startDelay</code>, the
     * function is called after that delay ends.
     * It takes care of the final initialization steps for the
     * animation.
     *
     *  <p>Overrides of this method should call the superclass method to ensure
     *  that internal mechanisms for the animation are set up correctly.</p>
     */
    @CallSuper
    void initAnimation() {
        if (!mInitialized) {
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].init();
            }
            mInitialized = true;
        }
    }

再往上一层看startAnimation方法,从注释中也能看出一点这个方法只是初始化并通过观察者

// If there's no start delay, init the animation and notify start listeners right away
// to be consistent with the previous behavior. Otherwise, postpone this until the first
// frame after the start delay.
startAnimation();

再回到这里,你会发现原来动画逻辑的开始是在则个位置,之前是被startAnimation这个方法名骗了

private void start(boolean playBackwards) {
            ......
            startAnimation();
            //默认情况下mSeekFraction =-1
            if (mSeekFraction == -1) {
                // No seek, start at play time 0. Note that the reason we are not using fraction 0
                // is because for animations with 0 duration, we want to be consistent with pre-N
                // behavior: skip to the final value immediately.
                setCurrentPlayTime(0);
            } else {
                setCurrentFraction(mSeekFraction);
            }
            ......
    }

fraction是动画执行的百分比,如果动画执行时长是0,那么就设置一步到位,否则就设置fraction为当前比例

    /**
     * Sets the position of the animation to the specified point in time. This time should
     * be between 0 and the total duration of the animation, including any repetition. If
     * the animation has not yet been started, then it will not advance forward after it is
     * set to this time; it will simply set the time to this value and perform any appropriate
     * actions based on that time. If the animation is already running, then setCurrentPlayTime()
     * will set the current playing time to this value and continue playing from that point.
     *
     * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
     */
    public void setCurrentPlayTime(long playTime) {
        float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
        setCurrentFraction(fraction);
    }
    /**
     * Sets the position of the animation to the specified fraction. This fraction should
     * be between 0 and the total fraction of the animation, including any repetition. That is,
     * a fraction of 0 will position the animation at the beginning, a value of 1 at the end,
     * and a value of 2 at the end of a reversing animator that repeats once. If
     * the animation has not yet been started, then it will not advance forward after it is
     * set to this fraction; it will simply set the fraction to this value and perform any
     * appropriate actions based on that fraction. If the animation is already running, then
     * setCurrentFraction() will set the current fraction to this value and continue
     * playing from that point. {@link Animator.AnimatorListener} events are not called
     * due to changing the fraction; those events are only processed while the animation
     * is running.
     *
     * @param fraction The fraction to which the animation is advanced or rewound. Values
     * outside the range of 0 to the maximum fraction for the animator will be clamped to
     * the correct range.
     */
    public void setCurrentFraction(float fraction) {
        initAnimation();
        //把fraction限制在一个正确的范围内,这个范围就是0-repeatCount+1
        fraction = clampFraction(fraction);
        mStartTimeCommitted = true; // do not allow start time to be compensated for jank
        //表示判断是否已经进入了动画循环中,这个判断不同于isRunning(),isRunning返回true
        //也可能没有进入动画循环,所以,这个判断更加准确,进入循环之后会给   
        //mLastFrameTime赋值,而mRunning = true是在startAnimation初始化动画的时候就设
        //置了,所以mRunning值的设置是早于mLastFrameTime的
        if (isPulsingInternal()) {
            long seekTime = (long) (getScaledDuration() * fraction);
            long currentTime = AnimationUtils.currentAnimationTimeMillis();
            // Only modify the start time when the animation is running. Seek fraction will ensure
            // non-running animations skip to the correct start time.
            mStartTime = currentTime - seekTime;
        } else {
            // If the animation loop hasn't started, or during start delay, the startTime will be
            // adjusted once the delay has passed based on seek fraction.
            mSeekFraction = fraction;
        }
        mOverallFraction = fraction;
        //获取本次循环当前动画执行的fraction,因为可能这个动画被设置要重复执行多次        
        final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
        animateValue(currentIterationFraction);
    }
    /**
     * Clamps fraction into the correct range: [0, mRepeatCount + 1]. If repeat count is infinite,
     * no upper bound will be set for the fraction.
     *
     * @param fraction fraction to be clamped
     * @return fraction clamped into the range of [0, mRepeatCount + 1]
     */
    private float clampFraction(float fraction) {
        if (fraction < 0) {
            fraction = 0;
        } else if (mRepeatCount != INFINITE) {
            fraction = Math.min(fraction, mRepeatCount + 1);
        }
        return fraction;
    }
    /**
     * Calculates the fraction of the current iteration, taking into account whether the animation
     * should be played backwards. E.g. When the animation is played backwards in an iteration,
     * the fraction for that iteration will go from 1f to 0f.
     */
    private float getCurrentIterationFraction(float fraction, boolean inReverse) {
        //在此验证fraction是否在合理范围,不在则限制其在合理范围
        fraction = clampFraction(fraction);
        //获取当前动画执行的第几个循环        
        int iteration = getCurrentIteration(fraction);
        //当前fraction,它可能是2.3,那么iteration则是2,2.3减去2得到的就是当前
        //本次循环的fraction        
        float currentFraction = fraction - iteration;
        //根据是否反向执行返回正确的fraction    
        return shouldPlayBackward(iteration, inReverse) ? 1f - currentFraction : currentFraction;
    }

mValues数组中存放的是FloatPropertyValuesHoler,我们可以在其父类PropertyValuesHolder中找到calculateValue方法

    /**
     * This method is called with the elapsed fraction of the animation during every
     * animation frame. This function turns the elapsed fraction into an interpolated fraction
     * and then into an animated value (from the evaluator. The function is called mostly during
     * animation updates, but it is also called when the <code>end()</code>
     * function is called, to set the final value on the property.
     *
     * <p>Overrides of this method must call the superclass to perform the calculation
     * of the animated value.</p>
     *
     * @param fraction The elapsed fraction of the animation.
     */
    @CallSuper
    void animateValue(float fraction) {
        fraction = mInterpolator.getInterpolation(fraction);
        mCurrentFraction = fraction;
        int numValues = mValues.length;
        //计算出fraction对应的值
        for (int i = 0; i < numValues; ++i) {
            mValues[i].calculateValue(fraction);
        }
        //这是我们设置的UpdateListener回调        
        if (mUpdateListeners != null) {
            int numListeners = mUpdateListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                mUpdateListeners.get(i).onAnimationUpdate(this);
            }
        }
    }

在PropertyValuesHolder中找到了这个方法,作用就是根据设置的差值器获取对应fraction的value

    /**
     * Function used to calculate the value according to the evaluator set up for
     * this PropertyValuesHolder object. This function is called by ValueAnimator.animateValue().
     *
     * @param fraction The elapsed, interpolated fraction of the animation.
     */
    void calculateValue(float fraction) {
        Object value = mKeyframes.getValue(fraction);
        mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
    }

但是我们会发现在他的子类中也都重写了这个方法,比如FloatPropertyValuesHolder是这样写的,直接从对象中取出对应的值,这个mFloatKeyframes是在ofFloat阶段创建出来的,具体怎么取值的,请自行阅读

@Override
void calculateValue(float fraction) {
      mFloatAnimatedValue = mFloatKeyframes.getFloatValue(fraction);
}

然后我们回到上边继续看UpdateListener的逻辑

 mUpdateListeners.get(i).onAnimationUpdate(this);

当这行代码执行的时候,我们设置的监听器就会收到回调,也就是终于回到了,这里了

valueAnimator.addUpdateListener(new AnimatorUpdateListener() {  
       @Override  
       public void onAnimationUpdate(ValueAnimator animator) {  
            //获得当前动画的进度值,整型,1-100之间  
           int currentValue = (Integer)animator.getAnimatedValue();  

       }  
});  

此时因为之前的一系列操作已经将每个fraction的值保存起来了,那么就可以如此获取了

public Object getAnimatedValue() {
        if (mValues != null && mValues.length > 0) {
            return mValues[0].getAnimatedValue();
        }
        // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
        return null;
    }
总结一下

ValueAnimator虽然是属性动画,但它并不帮我们做动画,它只是将每个阶段fraction对应的值通过差值器给我们计算出来并保存,然后动画的执行由我们去开启。

上一篇:Cool!15个创意的 CSS3 文本效果【下篇】


下一篇:一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!