Android Animator 源码分析

来源:互联网 发布:秋冬保湿水乳 知乎 编辑:程序博客网 时间:2024/06/05 14:20

关于Android 属性动画的使用,请见
http://blog.csdn.net/y874961524/article/details/53980165

下面分析下Animator在Framework层的实现

从ObjectAnimator.ofFloat()开始

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {    ObjectAnimator anim = new ObjectAnimator(target, propertyName);    anim.setFloatValues(values);    return anim;}

这个工厂方法会创建一个ObjectAnimator对象,在创建时同时设置属性动画的目标和属性名

private ObjectAnimator(Object target, String propertyName) {    setTarget(target);    setPropertyName(propertyName);}
// 设置目标对象@Overridepublic void setTarget(@Nullable Object target) {    final Object oldTarget = getTarget();    if (oldTarget != target) {        if (isStarted()) {            cancel();        }        // target必须是一个弱引用对象        mTarget = target == null ? null : new WeakReference<Object>(target);        // New target should cause re-initialization prior to starting        mInitialized = false; // 记录尚未初始化,ValueAnimator的标志位,一会要用    }}
// 设置属性名称public void setPropertyName(@NonNull String propertyName) {    // mValues could be null if this is being constructed piecemeal. Just record the    // propertyName to be used later when setValues() is called if so.    if (mValues != null) {        // 属性值的更新操作委托给PropertyValuesHolder进行        // Animator只进行数值计算        PropertyValuesHolder valuesHolder = mValues[0];        String oldName = valuesHolder.getPropertyName();        valuesHolder.setPropertyName(propertyName);        mValuesMap.remove(oldName);        mValuesMap.put(propertyName, valuesHolder);    }    mPropertyName = propertyName;    // New property/values/target should cause re-initialization prior to starting    mInitialized = false;}

ofFloat还有一步就是调用这个方法

@Overridepublic void setFloatValues(float... values) {    if (mValues == null || mValues.length == 0) {        // No values yet - this animator is being constructed piecemeal. Init the values with        // whatever the current propertyName is        // 这是mProperty是为null的         if (mProperty != null) {            setValues(PropertyValuesHolder.ofFloat(mProperty, values));        } else {   setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));        }    } else {        super.setFloatValues(values);    }}

setValues这个过程有点长,按照顺序先写下吧

// PropertyValueHolder中// 获取PropertyValuesHolderpublic static PropertyValuesHolder ofFloat(String propertyName, float... values) {    // 创建子类    return new FloatPropertyValuesHolder(propertyName, values);}public FloatPropertyValuesHolder(String propertyName, float... values) {    super(propertyName);    setFloatValues(values);}@Overridepublic void setFloatValues(float... values) {    // 这个过程会取得value的类型    super.setFloatValues(values);    mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;}// super.setFloatValues()// 取得Value的类型public void setFloatValues(float... values) {    mValueType = float.class;    mKeyframes = KeyframeSet.ofFloat(values);}

然后设置KeyFrame了,KeyFrame时属性动画中的关键帧,通过设置关键帧来保证动画执行时序性

// ~KeyFrameSet中public static KeyframeSet ofFloat(float... values) {    boolean badValue = false;    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]);        if (Float.isNaN(values[0])) {            badValue = true;        }    } 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]);            if (Float.isNaN(values[i])) {                badValue = true;            }        }    }    if (badValue) {        Log.w("Animator", "Bad value (NaN) in float animator");    }    // 创建一个关键帧集合    return new FloatKeyframeSet(keyframes);}

接下来看关键帧怎么创建的

//keyFrame中public static Keyframe ofFloat(float fraction) {    return new FloatKeyframe(fraction);}// FloatKeyFrame中FloatKeyframe(float fraction) {    mFraction = fraction;    mValueType = float.class;}

仔细看了看,发现KeyFrame其实只是对当前的value和fraction进行一个记录,不同类型的KeyFrame会设置不同的mValueType

KeyFrame中的属性值,一会回来再看

/** * Flag to indicate whether this keyframe has a valid value. This flag is used when an * animation first starts, to populate placeholder keyframes with real values derived * from the target object. */boolean mHasValue;/** * Flag to indicate whether the value in the keyframe was read from the target object or not. * If so, its value will be recalculated if target changes. */boolean mValueWasSetOnStart;/** * The time at which mValue will hold true. */float mFraction;/** * The type of the value in this Keyframe. This type is determined at construction time, * based on the type of the <code>value</code> object passed into the constructor. */Class mValueType;/** * The optional time interpolator for the interval preceding this keyframe. A null interpolator * (the default) results in linear interpolation over the interval. */private TimeInterpolator mInterpolator = null;

回来看哪个keyframe的ofFloat方法,最终会创建一个关键帧集合

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

ObjectAnimator的ofFloat过程就结束了,下面看下其他方法

setDuration()

设置动画的执行时间
这个就是将执行时间写入属性中,一会会用到

@Overridepublic ValueAnimator setDuration(long duration) {    if (duration < 0) {        throw new IllegalArgumentException("Animators cannot have negative duration: " +                duration);    }    mDuration = duration;    return this;}

setInterpolator()

设置插值器,默认的插值器是带有加速度的

// The time interpolator to be used if none is set on the animationprivate static final TimeInterpolator sDefaultInterpolator =        new AccelerateDecelerateInterpolator();
@Overridepublic void setInterpolator(TimeInterpolator value) {    if (value != null) {        mInterpolator = value;    } else {        mInterpolator = new LinearInterpolator();    }}

setEvaluator()

设置估值器
估值器实际上是在KeyFrame中使用的

public void setEvaluator(TypeEvaluator value) {   if (value != null && mValues != null && mValues.length > 0) {       mValues[0].setEvaluator(value);   }}
public void setEvaluator(TypeEvaluator evaluator) {    mEvaluator = evaluator;    mKeyframes.setEvaluator(evaluator);}
//KeyFrameSet中public void setEvaluator(TypeEvaluator evaluator) {    // 使用属性值进行保存    mEvaluator = evaluator;}

start()

开始分析开始动画的方法
从ObjectAnimator开始,会调用到ValueAnimator的start(boolean playBackwards)方法

// playBackwards 是否倒序播放,我们此时传入的是falseprivate void start(boolean playBackwards) {    if (Looper.myLooper() == null) {        throw new AndroidRuntimeException("Animators may only be run on Looper threads");    }    mReversing = playBackwards;    // Special case: reversing from seek-to-0 should act as if not seeked at all.    // mSeekFraction这个标志位,第一次启动动画时是-1,暂时不会进入    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;    // 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 = 0;    // 这里从线程中取出AnimatonHandler,一会分析    AnimationHandler animationHandler = AnimationHandler.getInstance();    animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));    // mStartedDelay指示这个动画是否已经从startDelay中开始执行。    // 这里mStartDelay=0可以顺利启动    if (mStartDelay == 0 || mSeekFraction >= 0) {        // 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.            // 第一次启动,设置当前启动时间为0            setCurrentPlayTime(0);        } else {            setCurrentFraction(mSeekFraction);        }    }}

AnimationHandler分析

AnimationHandler 是一个实现了Runnable接口的ValueAnimator内部类

从当前线程中取得AnimationHandler对象

public static AnimationHandler getInstance() {    if (sAnimatorHandler.get() == null) {        sAnimatorHandler.set(new AnimationHandler());    }    return sAnimatorHandler.get();}

然后注册了两个回调,看下具体方法

/** * Register to get a callback on the next frame after the delay. */public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {    if (mAnimationCallbacks.size() == 0) {        getProvider().postFrameCallback(mFrameCallback);    }    if (!mAnimationCallbacks.contains(callback)) {        mAnimationCallbacks.add(callback);    }    if (delay > 0) {        mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));    }}
interface AnimationFrameCallback {  /**    * Run animation based on the frame time.    * @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time    *                  base.    */    // 每一帧动画开始时回调   void doAnimationFrame(long frameTime);   /**    * This notifies the callback of frame commit time. Frame commit time is the time after    * traversals happen, as opposed to the normal animation frame time that is before    * traversals. This is used to compensate expensive traversals that happen as the    * animation starts. When traversals take a long time to complete, the rendering of the    * initial frame will be delayed (by a long time). But since the startTime of the    * animation is set before the traversal, by the time of next frame, a lot of time would    * have passed since startTime was set, the animation will consequently skip a few frames    * to respect the new frameTime. By having the commit time, we can adjust the start time to    * when the first frame was drawn (after any expensive traversals) so that no frames    * will be skipped.    *    * @param frameTime The frame time after traversals happen, if any, in the    *                  {@link SystemClock#uptimeMillis()} time base.    */    // 每一帧开始遍历时回调   void commitAnimationFrame(long frameTime);}

从ValueAnimator中看下具体实现

// 这里对每一帧进行处理,如果时从暂停恢复,将调整开始时间public final void doAnimationFrame(long frameTime) {    AnimationHandler handler = AnimationHandler.getInstance();    if (mLastFrameTime == 0) {        // First frame        handler.addOneShotCommitCallback(this);        if (mStartDelay > 0) {            startAnimation();        }        if (mSeekFraction < 0) {            mStartTime = frameTime;        } else {            long seekTime = (long) (getScaledDuration() * mSeekFraction);            mStartTime = frameTime - seekTime;            mSeekFraction = -1;        }        mStartTimeCommitted = false; // allow start time to be compensated for jank    }    mLastFrameTime = frameTime;    if (mPaused) {        mPauseTime = frameTime;        handler.removeCallback(this);        return;    } else if (mResumed) {        mResumed = false;        if (mPauseTime > 0) {            // Offset by the duration that the animation was paused            mStartTime += (frameTime - mPauseTime);            mStartTimeCommitted = false; // allow start time to be compensated for jank        }        handler.addOneShotCommitCallback(this);    }    // The frame time might be before the start time during the first frame of    // an animation.  The "current time" must always be on or after the start    // time to avoid animating frames at negative time intervals.  In practice, this    // is very rare and only happens when seeking backwards.    final long currentTime = Math.max(frameTime, mStartTime);    boolean finished = animateBasedOnTime(currentTime);    if (finished) {        endAnimation();    }}

这个回调也是遍历时调整启动时间的

public void commitAnimationFrame(long frameTime) {    if (!mStartTimeCommitted) {        mStartTimeCommitted = true;        long adjustment = frameTime - mLastFrameTime;        if (adjustment > 0) {            mStartTime += adjustment;            if (DEBUG) {                Log.d(TAG, "Adjusted start time by " + adjustment + " ms: " + toString());            }        }    }}

startAnimation()

这段代码时start()中真正启动动画的代码,必须在UI线程,仔细研究下

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;    }    if (mListeners != null) {        // 通知所有回调        notifyStartListeners();    }}

先会调用ObjectAnimator的initAnimation,只要是初始化反射的方法,对Target的属性值进行修改

@CallSuper@Overridevoid initAnimation() {    if (!mInitialized) {        // mValueType may change due to setter/getter setup; do this before calling super.init(),        // which uses mValueType to set up the default type evaluator.        final Object target = getTarget();        if (target != null) {            final int numValues = mValues.length;            for (int i = 0; i < numValues; ++i) {                mValues[i].setupSetterAndGetter(target);            }        }        super.initAnimation();    }}

PropertyValuesHolder的setupSetterAndGetter()

初始化反射修改器,这里代码有点多

void setupSetterAndGetter(Object target) {    mKeyframes.invalidateCache();    if (mProperty != null) {        // check to make sure that mProperty is on the class of target        // try-catch判断是否这个属性在这个类里        try {            Object testValue = null;            List<Keyframe> keyframes = mKeyframes.getKeyframes();            int keyframeCount = keyframes == null ? 0 : keyframes.size();            for (int i = 0; i < keyframeCount; i++) {                Keyframe kf = keyframes.get(i);                if (!kf.hasValue() || kf.valueWasSetOnStart()) {                    if (testValue == null) {                        testValue = convertBack(mProperty.get(target));                    }                    kf.setValue(testValue);                    kf.setValueWasSetOnStart(true);                }            }            return;        } catch (ClassCastException e) {            Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +                    ") on target object " + target + ". Trying reflection instead");            mProperty = null;        }    }    // 如果还没有找到属性的话,判断get和set方法是否存在    // We can't just say 'else' here because the catch statement sets mProperty to null.    if (mProperty == null) {        Class targetClass = target.getClass();        if (mSetter == null) {            // 初始化setter            setupSetter(targetClass);        }        List<Keyframe> keyframes = mKeyframes.getKeyframes();        int keyframeCount = keyframes == null ? 0 : keyframes.size();        for (int i = 0; i < keyframeCount; i++) {            Keyframe kf = keyframes.get(i);            if (!kf.hasValue() || kf.valueWasSetOnStart()) {                if (mGetter == null) {                    // 初始化getter                    setupGetter(targetClass);                    if (mGetter == null) {                        // Already logged the error - just return to avoid NPE                        return;                    }                }                try {                    Object value = convertBack(mGetter.invoke(target));                    kf.setValue(value);                    kf.setValueWasSetOnStart(true);                } catch (InvocationTargetException e) {                    Log.e("PropertyValuesHolder", e.toString());                } catch (IllegalAccessException e) {                    Log.e("PropertyValuesHolder", e.toString());                }            }        }    }}

继续寻找set和get方法

private Method setupSetterOrGetter(Class targetClass,        HashMap<Class, HashMap<String, Method>> propertyMapMap,        String prefix, Class valueType) {    Method setterOrGetter = null;    synchronized(propertyMapMap) {        // Have to lock property map prior to reading it, to guard against        // another thread putting something in there after we've checked it        // but before we've added an entry to it        HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);        boolean wasInMap = false;        if (propertyMap != null) {            wasInMap = propertyMap.containsKey(mPropertyName);            if (wasInMap) {                setterOrGetter = propertyMap.get(mPropertyName);            }        }        if (!wasInMap) {            // 通过属性值寻找方法            setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);            if (propertyMap == null) {                propertyMap = new HashMap<String, Method>();                propertyMapMap.put(targetClass, propertyMap);            }            // 放入map中            propertyMap.put(mPropertyName, setterOrGetter);        }    }    //返回给mSetter或mGetter    return setterOrGetter;}

然后调用ValueAnimator的initAnimation

这里会初始化每一个PropertyValuesHolder

void initAnimation() {    if (!mInitialized) {        int numValues = mValues.length;        for (int i = 0; i < numValues; ++i) {            // 这里会初始化每一个PropertyValuesHolder            mValues[i].init();        }        mInitialized = true;    }}

PropertyValuesHolder中的init()

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        // 给每一个KeyFrame设置估值器,前面讲过        mKeyframes.setEvaluator(mEvaluator);    }}

start()中的setCurrentPlayTime()

start()中调用的启动动画方法

public void setCurrentPlayTime(long playTime) {    // 计算fraction    float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;    setCurrentFraction(fraction);}
// 将计算出来的Fraction设置给动画public void setCurrentFraction(float fraction) {    initAnimation();    fraction = clampFraction(fraction);    long seekTime = (long) (getScaledDuration() * fraction);    // 当前执行动画的时间    long currentTime = AnimationUtils.currentAnimationTimeMillis();    mStartTime = currentTime - seekTime;    mStartTimeCommitted = true; // do not allow start time to be compensated for jank    if (!isPulsingInternal()) {        // If the animation loop hasn't started, the startTime will be adjusted in the first        // frame based on seek fraction.        mSeekFraction = fraction;    }    mOverallFraction = fraction;    final float currentIterationFraction = getCurrentIterationFraction(fraction);    // 拿到Fraction以后,开始变化数值    animateValue(currentIterationFraction);}

对动画数值进行运算

先会调用ObjectAnimator中的animateValue

@Overridevoid animateValue(float fraction) {    final Object target = getTarget();    if (mTarget != null && target == null) {        // We lost the target reference, cancel and clean up.        cancel();        return;    }    // 这里调用ValueAnimator中的animateValue计算数值    // ValueAnimator与属性值无关的,一会再看    super.animateValue(fraction);    int numValues = mValues.length;    //反射修改每个方法值    //这里修改完这一轮动画就结束了    for (int i = 0; i < numValues; ++i) {        mValues[i].setAnimatedValue(target);    }}

ValueAnimator中的animateValue进行插值运算

void animateValue(float fraction) {    // 插值运算在这里    fraction = mInterpolator.getInterpolation(fraction);    // 获取当前的Fraction    mCurrentFraction = fraction;    int numValues = mValues.length;    for (int i = 0; i < numValues; ++i) {        // 对每个PropertyValuesHolder计算数值        mValues[i].calculateValue(fraction);    }    // 回调update监听器    if (mUpdateListeners != null) {        int numListeners = mUpdateListeners.size();        for (int i = 0; i < numListeners; ++i) {            mUpdateListeners.get(i).onAnimationUpdate(this);        }    }}

PropertyValuesHolder中的calculateValue()

通过获取的fraction,对每个属性值进行变化,这个过程通过反射进行

void calculateValue(float fraction) {   // 从KeyFrame中获取计算完成的属性值,我们来看下这个方法   Object value = mKeyframes.getValue(fraction);   // 这里取到属性值   mAnimatedValue = mConverter == null ? value : mConverter.convert(value);}

KeyFrameSet中的getValue()

//KeyFrameSet中public Object getValue(float fraction) {    // Special-case optimization for the common case of only two keyframes    // 只有两个关键帧的情况    if (mNumKeyframes == 2) {        if (mInterpolator != null) {            fraction = mInterpolator.getInterpolation(fraction);        }        // 通过估值器进行取值        return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),                mLastKeyframe.getValue());    }    // 此处处理多个关键帧的情况,取出俩个关键帧之前的Fraction    // 进行计算    if (fraction <= 0f) {        final Keyframe nextKeyframe = mKeyframes.get(1);        final TimeInterpolator interpolator = nextKeyframe.getInterpolator();        if (interpolator != null) {            fraction = interpolator.getInterpolation(fraction);        }        final float prevFraction = mFirstKeyframe.getFraction();        float intervalFraction = (fraction - prevFraction) /            (nextKeyframe.getFraction() - prevFraction);        return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),                nextKeyframe.getValue());    } else if (fraction >= 1f) {        final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);        final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();        if (interpolator != null) {            fraction = interpolator.getInterpolation(fraction);        }        final float prevFraction = prevKeyframe.getFraction();        float intervalFraction = (fraction - prevFraction) /            (mLastKeyframe.getFraction() - prevFraction);        return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),                mLastKeyframe.getValue());    }    Keyframe prevKeyframe = mFirstKeyframe;    // 对两个关键帧之前的fraction使用估值器进行计算    for (int i = 1; i < mNumKeyframes; ++i) {        Keyframe nextKeyframe = mKeyframes.get(i);        if (fraction < nextKeyframe.getFraction()) {            final TimeInterpolator interpolator = nextKeyframe.getInterpolator();            final float prevFraction = prevKeyframe.getFraction();            float intervalFraction = (fraction - prevFraction) /                (nextKeyframe.getFraction() - prevFraction);            // Apply interpolator on the proportional duration.            if (interpolator != null) {                intervalFraction = interpolator.getInterpolation(intervalFraction);            }            return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),                    nextKeyframe.getValue());        }        prevKeyframe = nextKeyframe;    }    // shouldn't reach here    return mLastKeyframe.getValue();}

PropertyValueHolder中的setAnimatedValue()反射修改属性值

如果是ofFloat创建的FloatPropertyValueHolder,那么该方法为

@Overridevoid setAnimatedValue(Object target) {    if (mFloatProperty != null) {        mFloatProperty.setValue(target, mFloatAnimatedValue);        return;    }    if (mProperty != null) {        mProperty.set(target, mFloatAnimatedValue);        return;    }    // 针对jni属性    if (mJniSetter != 0) {        nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);        return;    }    // 反射修改数值    if (mSetter != null) {        try {            mTmpValueArray[0] = mFloatAnimatedValue;            mSetter.invoke(target, mTmpValueArray);        } catch (InvocationTargetException e) {            Log.e("PropertyValuesHolder", e.toString());        } catch (IllegalAccessException e) {            Log.e("PropertyValuesHolder", e.toString());        }    }}

动画流程就是这样

0 0
原创粉丝点击