ValueAnimator 源码分析

ValueAnimator 是继承 Animator 这个抽象类,Animator 中定义了一些回调即回调接口的集合,这个里面没什么具体内容,大部分都是抽象类,这里体现了动画整体的框架,需要注意的是 resume() 和 pause() 这个两个方法,它俩不经常用,意思是恢复和暂停,比如当前页面被覆盖了,则暂停动画;重新获取焦点了,则恢复动画。

对于 ValueAnimator 的简单用法,它其实不会直接对view进行动画,而是辅助性的提供出数据及不间断的回调,具体动画我们自己来调用,比如对于view的x轴的缩放动画
    

    private void scaleView(final View view){
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float xValue = (float) animation.getAnimatedValue();
                view.setScaleX(xValue);
            }
        });
        valueAnimator.setDuration(2000);
        valueAnimator.start();
    }

这样动画效果就出现了,但它的数据是怎么计算的呢?通过源码分析分析。

    public static ValueAnimator ofFloat(float... values) {
        ValueAnimator anim = new ValueAnimator();
        anim.setFloatValues(values);
        return anim;
    }


这里使用的是 ValueAnimator 的无参构造方法,注意设置数据的方法

    public void setFloatValues(float... values) {
        if (values == null || values.length == 0) {
            return;
        }
        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;
    }

    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];
            mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
        }
        // New property/values/target should cause re-initialization prior to starting
        mInitialized = false;
    }

第一进来时,mValues 为 null,则执行 setValues(PropertyValuesHolder.ofFloat("", values))  方法,这里是创建一个 PropertyValuesHolder 对象,把 values 值封装进去,然后把 PropertyValuesHolder 对象添加到 mValuesMap 集合中,key 值是 PropertyValuesHolder.ofFloat("", values) 中的第一个参数;setValues() 方法看完了,继续往下看,这里的意思如果之前 PropertyValuesHolder 已经有值了,这里直接复用,替换 values 值。接着看看 PropertyValuesHolder.ofFloat("", values) 方法的源码

    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
        return new FloatPropertyValuesHolder(propertyName, values);
    }
    public void setFloatValues(float... values) {
        mValueType = float.class;
        mKeyframes = KeyframeSet.ofFloat(values);
    }
    
    static class FloatPropertyValuesHolder extends PropertyValuesHolder {
        ...
        public FloatPropertyValuesHolder(String propertyName, float... values) {
            super(propertyName);
            setFloatValues(values);
        }

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

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

最终创建 FloatPropertyValuesHolder 对象,它是 PropertyValuesHolder 的子类,构造器里调用父类的 setFloatValues(values) 方法,产生了 mKeyframes 对象,
    

    public static KeyframeSet ofFloat(float... values) {
        int numKeyframes = values.length;
        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]);
        } else {
            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]);
            }
        }
        return new FloatKeyframeSet(keyframes);
    }

在这里会把 values 数据再次封装到 Keyframe 中,创建出来 Keyframe 对象添加到数组中,然后创建子类 FloatKeyframeSet。先看 Keyframe.ofFloat(0f) 源码

static class FloatKeyframe extends Keyframe {
    float mValue;

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

    FloatKeyframe(float fraction) {
        mFraction = fraction;
        mValueType = float.class;
    }

    public float getFloatValue() {
        return mValue;
    }
    ...
}


里面明显的值是 mValue,默认值为 0f,构造方法可以传参赋值,此时我们明白了,ValueAnimator.ofFloat(0f, 1f) 中的 0f 和 1f,对应这里两个 FloatKeyframe 对象中的 mValue 值。 再看看 FloatKeyframeSet 这个类,构造方法中把 FloatKeyframe 数组传了进去

class KeyframeSet implements Keyframes {

    int mNumKeyframes;
    Keyframe mFirstKeyframe;
    Keyframe mLastKeyframe;
    TimeInterpolator mInterpolator; // only used in the 2-keyframe case
    List<Keyframe> mKeyframes; // only used when there are not 2 keyframes
    TypeEvaluator mEvaluator;

    public KeyframeSet(Keyframe... keyframes) {
        mNumKeyframes = keyframes.length;
        mKeyframes = Arrays.asList(keyframes);
        mFirstKeyframe = keyframes[0];
        mLastKeyframe = keyframes[mNumKeyframes - 1];
        mInterpolator = mLastKeyframe.getInterpolator();
    }
    ...
}

class FloatKeyframeSet extends KeyframeSet implements Keyframes.FloatKeyframes {
    private float firstValue;
    private float lastValue;
    private float deltaValue;
    private boolean firstTime = true;

    public FloatKeyframeSet(FloatKeyframe... keyframes) {
        super(keyframes);
    }

    @Override
    public Object getValue(float fraction) {
        return getFloatValue(fraction);
    }

    @Override
    public float getFloatValue(float fraction) {
        if (mNumKeyframes == 2) {
            if (firstTime) {
                firstTime = false;
                firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue();
                lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue();
                deltaValue = lastValue - firstValue;
            }
            if (mInterpolator != null) {
                fraction = mInterpolator.getInterpolation(fraction);
            }
            if (mEvaluator == null) {
                return firstValue + fraction * deltaValue;
            } else {
                return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue();
            }
        }
        ...
        return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
    }
}

这里有几点要注意: 
一、父类 KeyframeSet 中 mInterpolator 插值器是通过最后一个 Keyframe 对象中获取的,但是在这个案例中,它没有被赋值,为null;
二、FloatKeyframeSet 对外提供数据时,最终调用 getFloatValue() 方法,为了好理解,我把代码简化了;
三、getFloatValue() 方法中,会算出两个数据的差值 deltaValue,然后根据进度 fraction 来计算当前的值;
四、mInterpolator 这里为null,看 mEvaluator 估值器,如果为nul。则是匀速变化;如果不为null,我们自定义了,则使用我们自定义的方法;再这个案例中,实际上是有值的,传递地方后面分析,这里先说一下 FloatEvaluator 的源码

public class FloatEvaluator implements TypeEvaluator<Number> {
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}


也是匀速变化的。分析到这,大概明白数据是怎么变化的,假如说有个Handler,每隔16毫秒就发送个Runnable,调用 getFloatValue(float fraction) 方法获取数据,而 fraction 是进度,从 0% 增加到 100%,那么我们获取到 float xValue = (float) animation.getAnimatedValue() 的值是不是就对应上了?数据变化的逻辑大概知道了,那么它是怎么引起变化的?

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f) 这行代码分析完了,剩下的是设置回调和时间,没什么好说的,关键是 valueAnimator.start() 方法

    public void start() {
        start(false);
    }

    private void start(boolean playBackwards) {
        ...
        AnimationHandler animationHandler = getOrCreateAnimationHandler();
        animationHandler.mPendingAnimations.add(this);
        if (mStartDelay == 0) {
            if (prevPlayingState != SEEKED) {
                setCurrentPlayTime(0);
            }
            mPlayingState = STOPPED;
            mRunning = true;
            notifyStartListeners();
        }
        animationHandler.start();
    }


简化后的代码,if 语句中会执行 setCurrentPlayTime(0) 方法,notifyStartListeners() 方法是触发 onAnimationStart() 的监听回调;看看  setCurrentPlayTime(0) 源码

    public void setCurrentPlayTime(long playTime) {
        float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1;
        setCurrentFraction(fraction);
    }

    public void setCurrentFraction(float fraction) {
        initAnimation();
        int iteration = (int) fraction;
        ...
        long seekTime = (long) (mDuration * fraction);
        long currentTime = AnimationUtils.currentAnimationTimeMillis();
        mStartTime = currentTime - seekTime;
        mStartTimeCommitted = true; // do not allow start time to be compensated for jank
        if (mPlayingState != RUNNING) {
            mSeekFraction = fraction;
            mPlayingState = SEEKED;
        }
        animateValue(fraction);
    }


这个方法中中间的是计算时间的,先看看 initAnimation() 方法

    void initAnimation() {
        if (!mInitialized) {
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].init();
            }
            mInitialized = true;
        }
    }


这里的 mValues[0] 就是上面创建的 PropertyValuesHolder 对象,看看它里面被调用方法的源码

    void init() {
        if (mEvaluator == null) {
            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : (mValueType == Float.class) ? sFloatEvaluator : null;
        }
        if (mEvaluator != null) {
            mKeyframes.setEvaluator(mEvaluator);
        }
    }


分析 FloatKeyframeSet 中提到有几点要注意,第四条中说 mEvaluator 是有值的,就是这里传递的; 再看看setCurrentFraction() 方法中最后一行代码 animateValue(fraction) 方法,这里 fraction 值为0

    void animateValue(float fraction) {
        fraction = mInterpolator.getInterpolation(fraction);
        mCurrentFraction = fraction;
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].calculateValue(fraction);
        }
        if (mUpdateListeners != null) {
            int numListeners = mUpdateListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                mUpdateListeners.get(i).onAnimationUpdate(this);
            }
        }
    }

注意点四种也提到了 FloatKeyframeSet中 插值器 mInterpolator  为null,那么插值器如果调用了是在哪里工作的?答案就在这里,它有个默认值 AccelerateDecelerateInterpolator,如果想匀速变化,我们可以通过 setInterpolator() 方法来设置自己的插值器;继续往下看,发现 mValues[i].calculateValue(fraction) 方法,对象是 FloatPropertyValuesHolder,所以对应的源码是

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

看到这,就明白了,mFloatKeyframes 就是 FloatKeyframeSet 对象,这里的 getFloatValue(fraction) 就是上面我们分析的那个方法。animateValue()最下面的是进度的回调,也就是我们通过 valueAnimator.addUpdateListener() 设置的这个回调,

animation.getAnimatedValue() 对应的是 

    public Object getAnimatedValue() {
        if (mValues != null && mValues.length > 0) {
            return mValues[0].getAnimatedValue();
        }
        return null;
    }


看看 FloatPropertyValuesHolder 中的方法

    Object getAnimatedValue() {
        return mFloatAnimatedValue;
    }


mFloatAnimatedValue 这个值就是上面的 calculateValue(float fraction) 中获取的,在这里直接使用。


start() 中剩余最后一行代码,重点看看 animationHandler.start()

    public void start() {
        scheduleAnimation();
    }
    private void scheduleAnimation() {
        if (!mAnimationScheduled) {
            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
            mAnimationScheduled = true;
        }
    }
    final Runnable mAnimate = new Runnable() {
        @Override
        public void run() {
            mAnimationScheduled = false;
            doAnimationFrame(mChoreographer.getFrameTime());
        }
    };


AnimationHandler 是个内部静态类,关键还是 doAnimationFrame() 方法,同时注意用到了 Choreographer 这个类

    void doAnimationFrame(long frameTime) {
        mLastFrameTime = frameTime;
        while (mPendingAnimations.size() > 0) {
            ArrayList<ValueAnimator> pendingCopy = (ArrayList<ValueAnimator>) mPendingAnimations.clone();
            mPendingAnimations.clear();
            int count = pendingCopy.size();
            for (int i = 0; i < count; ++i) {
                ValueAnimator anim = pendingCopy.get(i);
                if (anim.mStartDelay == 0) {
                    anim.startAnimation(this);
                } else {
                    mDelayedAnims.add(anim);
                }
            }
        }
        ...
        int numAnims = mAnimations.size();
        for (int i = 0; i < numAnims; ++i) {
            mTmpAnimations.add(mAnimations.get(i));
        }
        for (int i = 0; i < numAnims; ++i) {
            ValueAnimator anim = mTmpAnimations.get(i);
            if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
                mEndingAnims.add(anim);
            }
        }
        ...
        mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mCommit, null);
        if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
            scheduleAnimation();
        }
    }

第一次进来,会执行 while (mPendingAnimations.size() > 0) 循环,因为在 start() 时,animationHandler.mPendingAnimations. add(this),所以此时集合里面有对象;这是后会把它里面的元素clone到 pendingCopy 集合中,然后把 mPendingAnimations 清空,然后for循环,调用 startAnimation() 方法

    private void startAnimation(AnimationHandler handler) {
        initAnimation();
        handler.mAnimations.add(this);
        if (mStartDelay > 0 && mListeners != null) {
            notifyStartListeners();
        }
    }


initAnimation() 和 notifyStartListeners() 方法内部都有防护,不会被多次执行,这里重点关注 handler.mAnimations.add(this) 这行代码;回归主方法,会计算出 mAnimations 中的元素个数 numAnims,然后遍历元素,调用 ValueAnimator 的 doAnimationFrame(frameTime) 方法

    final boolean doAnimationFrame(long frameTime) {
        ...
        final long currentTime = Math.max(frameTime, mStartTime);
        return animationFrame(currentTime);
    }
    
    boolean animationFrame(long currentTime) {
        boolean done = false;
        switch (mPlayingState) {
        case RUNNING:
        case SEEKED:
            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
            ...
            animateValue(fraction);
            break;
        }
        return done;
    }


对于我们目前的逻辑,可以简化成这样,animateValue(float fraction) 方法上面讲过了,它是用来更新数据的,mChoreographer. postCallback(Choreographer.CALLBACK_COMMIT,mCommit, null) 这行代码是用来矫正动画开始时间的,可以忽略。最后三行代码,注意 scheduleAnimation() 方法,mAnimations 集合不为空时会被调用,看看它做了什么

    private void scheduleAnimation() {
        if (!mAnimationScheduled) {
            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
            mAnimationScheduled = true;
        }
    }
    final Runnable mAnimate = new Runnable() {
        @Override
        public void run() {
            mAnimationScheduled = false;
            doAnimationFrame(mChoreographer.getFrameTime());
        }
    };

宿命的轮回,又回到了 doAnimationFrame() 这个方法,此时 mChoreographer.getFrameTime() 获取的时间是当前帧开始的时间,Choreographer 每隔16毫秒刷新一次,这样,就形成了一个循环,直到时间到了,才会停止。


 

发布了176 篇原创文章 · 获赞 11 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Deaht_Huimie/article/details/101710319