美文网首页
21.源码阅读(属性动画ValueAnimator-api26)

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

作者: 任振铭 | 来源:发表于2018-07-29 16:38 被阅读41次

    通常用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对应的值通过差值器给我们计算出来并保存,然后动画的执行由我们去开启。

    相关文章

      网友评论

          本文标题:21.源码阅读(属性动画ValueAnimator-api26)

          本文链接:https://www.haomeiwen.com/subject/shnzmftx.html