Android属性动画源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013928412/article/details/82557925

这篇文章主要讲解一些属性动画的源码,通过此篇文章能够帮助我们更好的理解和使用属性动画。

1、基本使用

我们先看下属性的动画的基本使用,并依此为入口,逐步分析属性动画的源码:

ObjectAnimator
        .ofInt(target,propName,values[])
            .setInterpolator(LinearInterpolator)
  .setEvaluator(IntEvaluator)
  .setDuration(500)
  .start();

上面就是属性动画的基本使用,先通过ObjectAnimator的静态方法ofInt新建ObjectAnimator对象,并传入构造参数,target:要操作的View,propName:要操作的View的属性,values[]:动画在执行期间将要使用的一系列值,构造完对象之后,通过setEvaluator设置插值器,设置执行时间,最后start执行,那么我们就先从构造方法开始一步一步分析

2、源码分析

1、ofInt

我们首先看下ofInt的代码:

public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
    ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    anim.setIntValues(values);
    return anim;
}

new了一个ObjectAnimator对象,并传入target和propertyName,来看看构造方法

private ObjectAnimator(Object target, String propertyName) {
    setTarget(target);
    setPropertyName(propertyName);
}
public void setTarget(@Nullable Object target) {
    final Object oldTarget = getTarget();
    if (oldTarget != target) {
        if (isStarted()) {
            cancel();
        }
        mTarget = target == null ? null : new WeakReference<Object>(target);
        // New target should cause re-initialization prior to starting
        mInitialized = false;
    }
}
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 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;
}

其实就是记录下target和propertyName;

构建完构造方法之后,调用了setIntValues;

@Override
public void setIntValues(int... 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
        if (mProperty != null) {
            setValues(PropertyValuesHolder.ofInt(mProperty, values));
        } else {
            setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
        }
    } else {
        super.setIntValues(values);
    }
}

调用setValues,并传入PropertyValuesHolder.ofInt(mPropertyName, values)参数,其实就是将values封装成PropertyValuesHolder,我们来看看PropertyValuesHolder.ofInt方法

public static PropertyValuesHolder ofInt(String propertyName, int... values) {
    return new IntPropertyValuesHolder(propertyName, values);
}

实例化了一个IntPropertyValuesHolder对象

public IntPropertyValuesHolder(String propertyName, int... values) {
    super(propertyName);
    setIntValues(values);
}
private PropertyValuesHolder(String propertyName) {
    mPropertyName = propertyName;
}

在IntPropertyValuesHolder构造方法中,保存propertyName,并调用setIntValues方法,来看看这个方法:

@Override
public void setIntValues(int... values) {
    super.setIntValues(values);
    mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
}

调用了父类的setIntValues方法,并将mIntKeyframes赋值,我们继续看看super.setIntValues方法

public void setIntValues(int... values) {
    mValueType = int.class;
    mKeyframes = KeyframeSet.ofInt(values);
}

调用了KeyframeSet.ofInt方法,

public static KeyframeSet ofInt(int... values) {
    int numKeyframes = values.length;
    IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
    if (numKeyframes == 1) {
        keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
        keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
    } else {
        keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
        for (int i = 1; i < numKeyframes; ++i) {
            keyframes[i] =
                    (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
        }
    }
    return new IntKeyframeSet(keyframes);
}

这个就是比较关键的部分了,先获取values的长度,并实例化一个keyframes数组,最小长度是2,如果传入的values的长度等于1,则将keyframes的第一个数设置为0,第二个数设置为传入的values值,否则,就遍历传入的值,将values里面的值,均匀的赋值给keyframes,最后返回intKeyFrameSet。

至此,ofInt的源码已经分析完了,我们稍微总结一下,ObjectAnimator将传入的target和propertyName保存起来,然后通过propertyName和values构建PropertyValuesHolders,进一步的将values中的数值按照关键帧的形式存储在PropertyValuesHolder中的KeyFrameSet中,这一部分主要是做存储操作

2、setInterpolator

setInterpolator其实调用的是父类ValueAnimator的方法,

@Override
public void setInterpolator(TimeInterpolator value) {
    if (value != null) {
        mInterpolator = value;
    } else {
        mInterpolator = new LinearInterpolator();
    }
}

仅仅是记录下插值器

3、setEvaluator

public void setEvaluator(TypeEvaluator value) {
    if (value != null && mValues != null && mValues.length > 0) {
        mValues[0].setEvaluator(value);
    }
}

设置了mValues的估值算法,也就是调用了PropertyValuesHolder的setEvaluator

public void setEvaluator(TypeEvaluator evaluator) {
    mEvaluator = evaluator;
    mKeyframes.setEvaluator(evaluator);
}

设置给了PropertyValuesHolder和KeyframeSet

4、setDuration

@NonNull
public ObjectAnimator setDuration(long duration) {
    super.setDuration(duration);
    return this;
}
@Override
public ValueAnimator setDuration(long duration) {
    if (duration < 0) {
        throw new IllegalArgumentException("Animators cannot have negative duration: " +
                duration);
    }
    mUnscaledDuration = duration;
    updateScaledDuration();
    return this;
}

仅仅是保存了一下动画的执行时间,也没什么好说的

5、start

@Override
public void start() {
    // See if any of the current active/pending animators need to be canceled
    AnimationHandler handler = sAnimationHandler.get();
    if (handler != null) {
        int numAnims = handler.mAnimations.size();
        for (int i = numAnims - 1; i >= 0; i--) {
            if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
                ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
                if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                    anim.cancel();
                }
            }
        }
        numAnims = handler.mPendingAnimations.size();
        for (int i = numAnims - 1; i >= 0; i--) {
            if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
                ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
                if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                    anim.cancel();
                }
            }
        }
        numAnims = handler.mDelayedAnims.size();
        for (int i = numAnims - 1; i >= 0; i--) {
            if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
                ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
                if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                    anim.cancel();
                }
            }
        }
    }
    if (DBG) {
        Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
        for (int i = 0; i < mValues.length; ++i) {
            PropertyValuesHolder pvh = mValues[i];
            Log.d(LOG_TAG, "   Values[" + i + "]: " +
                pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
                pvh.mKeyframes.getValue(1));
        }
    }
    super.start();
}

先是从本线程中取出AnimationHandler,然后做一些cancel操作,最后调用super.start,AnimationHandler是ValueAnimation的内部类(不用的api可能不太一样,当前api版本是23)

再来看看ValueAnimator的start方法

@Override
public void start() {
    start(false);
}
private void start(boolean playBackwards) {
    if (Looper.myLooper() == null) {
        throw new AndroidRuntimeException("Animators may only be run on Looper threads");
    }
//当前动画是否是reverse;
    mReversing = playBackwards;
    mPlayingBackwards = playBackwards;
    if (playBackwards && mSeekFraction != -1) {
        if (mSeekFraction == 0 && mCurrentIteration == 0) {
            // special case: reversing from seek-to-0 should act as if not seeked at all
            mSeekFraction = 0;
        } else if (mRepeatCount == INFINITE) {
            mSeekFraction = 1 - (mSeekFraction % 1);
        } else {
            mSeekFraction = 1 + mRepeatCount - (mCurrentIteration + mSeekFraction);
        }
        mCurrentIteration = (int) mSeekFraction;
        mSeekFraction = mSeekFraction % 1;
    }
//mCurrentIteration 记录当前的动画的执行次数(与setRepeatCount有关)
    if (mCurrentIteration > 0 && mRepeatMode == REVERSE &&
            (mCurrentIteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) {
        // if we were seeked to some other iteration in a reversing animator,
        // figure out the correct direction to start playing based on the iteration
        if (playBackwards) {
            mPlayingBackwards = (mCurrentIteration % 2) == 0;
        } else {
            mPlayingBackwards = (mCurrentIteration % 2) != 0;
        }
    }
    int prevPlayingState = mPlayingState;
//stop状态
    mPlayingState = STOPPED;
    mStarted = true;
    mStartedDelay = false;
    mPaused = false;
    updateScaledDuration(); // in case the scale factor has changed since creation time
//从当前线程获取AnimationHandler
    AnimationHandler animationHandler = getOrCreateAnimationHandler();
//将此Animator添加到animationHandler的mPendingAnimations,这个变量是ArrayList<ValueAnimator>类型的
    animationHandler.mPendingAnimations.add(this);
//如果没有延迟
    if (mStartDelay == 0) {
        // This sets the initial value of the animation, prior to actually starting it running

        if (prevPlayingState != SEEKED) {
//执行这个方法,下面去分析
            setCurrentPlayTime(0);
        }
//设置状态
        mPlayingState = STOPPED;
        mRunning = true;
//如果设置了AnimatorListener则会回调onAnimationStart方法
        notifyStartListeners();
    }
//调用animation.start方法, 一会分析
    animationHandler.start();
}

最终调用了start(false)方法,这段代码有点长,其实就是设置一些状态,将这个Animator放到AnimationHandler的执行队列中,回调onAnimationStart方法

我们来看看setCurrentPlayTime(0):

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

通过playTime计算出fraction,然后作为参数传递给setCurrnetFraction

public void setCurrentFraction(float fraction) {
//调用initAnimation,其实就是调用遍历values,给每个值调用PropertyValuesHolder的init方法,来设置mEvaluator估值器
    initAnimation();
    if (fraction < 0) {
        fraction = 0;
    }
    int iteration = (int) fraction;
    if (fraction == 1) {
        iteration -= 1;
    } else if (fraction > 1) {
        if (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE) {
            if (mRepeatMode == REVERSE) {
                mPlayingBackwards = (iteration % 2) != 0;
            }
            fraction = fraction % 1f;
        } else {
            fraction = 1;
            iteration -= 1;
        }
    } else {
        mPlayingBackwards = mReversing;
    }
    mCurrentIteration = iteration;
    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;
    }
    if (mPlayingBackwards) {
        fraction = 1f - fraction;
    }
    animateValue(fraction);
}

最后调用animateValue方法

void animateValue(float fraction) {
    final Object target = getTarget();
    if (mTarget != null && target == null) {
        // We lost the target reference, cancel and clean up.
        cancel();
        return;
    }
调用父类animateValue
    super.animateValue(fraction);
    int numValues = mValues.length;
    for (int i = 0; i < numValues; ++i) {
//为target设置属性值
        mValues[i].setAnimatedValue(target);
    }
}
super.animateValue:
void animateValue(float fraction) {
//使用我们设置的插值器mInterpolator通过fraction来转化成动画完成度
    fraction = mInterpolator.getInterpolation(fraction);
    mCurrentFraction = fraction;
    int numValues = mValues.length;
    for (int i = 0; i < numValues; ++i) {
//然后在将fraction交给估值算法mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();进行计算得到当前时间点,属性应该的值;最后会反射对我们设置的属性进行设置。
        mValues[i].calculateValue(fraction);
    }
    if (mUpdateListeners != null) {
        int numListeners = mUpdateListeners.size();
        for (int i = 0; i < numListeners; ++i) {
//回调onAnimationUpdate
            mUpdateListeners.get(i).onAnimationUpdate(this);
        }
    }
}

在其内部,调用了mKeyframeSet的getValue,这里注意我们的IntKeyFrameSet,千万不要看错方法了。

@Override
public Object getValue(float fraction) {
    return getIntValue(fraction);
}
@Override
public int getIntValue(float fraction) {
    if (mNumKeyframes == 2) {
        if (firstTime) {
            firstTime = false;
            firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
            lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
            deltaValue = lastValue - firstValue;
        }
        if (mInterpolator != null) {
            fraction = mInterpolator.getInterpolation(fraction);
        }
        if (mEvaluator == null) {
            return firstValue + (int)(fraction * deltaValue);
        } else {
            return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
        }
    }
    
    //省略代码。。
}

在其内部,因为我们只设置了一个目标属性值,所以只有两个关键帧;

setCurrentPlayTime已经设置完了,下面我们回到初始地方来看看animationHandler.start方法

public void start() {
    scheduleAnimation();
}
private void scheduleAnimation() {
    if (!mAnimationScheduled) {
        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
        mAnimationScheduled = true;
    }
}
start方法调用了scheduleAnimation方法,最终Choreographer调用postCallback,我们来啊看你mAnimate:
final Runnable mAnimate = new Runnable() {
    @Override
    public void run() {
        mAnimationScheduled = false;
        doAnimationFrame(mChoreographer.getFrameTime());
    }
};
最终Choreographer肯定会回调这个run方法,继续来看doAnimationFrame:
void doAnimationFrame(long frameTime) {
    mLastFrameTime = frameTime;

    // mPendingAnimations holds any animations that have requested to be started
    // We're going to clear mPendingAnimations, but starting animation may
    // cause more to be added to the pending list (for example, if one animation
    // starting triggers another starting). So we loop until mPendingAnimations
    // is empty.
    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 the animation has a startDelay, place it on the delayed list
            if (anim.mStartDelay == 0) {
                anim.startAnimation(this);
            } else {
                mDelayedAnims.add(anim);
            }
        }
    }

    // Next, process animations currently sitting on the delayed queue, adding
    // them to the active animations if they are ready
    int numDelayedAnims = mDelayedAnims.size();
    for (int i = 0; i < numDelayedAnims; ++i) {
        ValueAnimator anim = mDelayedAnims.get(i);
        if (anim.delayedAnimationFrame(frameTime)) {
            mReadyAnims.add(anim);
        }
    }
    int numReadyAnims = mReadyAnims.size();
    if (numReadyAnims > 0) {
        for (int i = 0; i < numReadyAnims; ++i) {
            ValueAnimator anim = mReadyAnims.get(i);
            anim.startAnimation(this);
            anim.mRunning = true;
            mDelayedAnims.remove(anim);
        }
        mReadyAnims.clear();
    }

    // Now process all active animations. The return value from animationFrame()
    // tells the handler whether it should now be ended
    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);
        }
    }
    mTmpAnimations.clear();
    if (mEndingAnims.size() > 0) {
        for (int i = 0; i < mEndingAnims.size(); ++i) {
            mEndingAnims.get(i).endAnimation(this);
        }
        mEndingAnims.clear();
    }

    // Schedule final commit for the frame.
    mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mCommit, null);

    // If there are still active or delayed animations, schedule a future call to
    // onAnimate to process the next frame of the animations.
    if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
        scheduleAnimation();
    }
}

while循环,遍历所有的mPendingAnimations中的ObjectAnimator,依此调用anim.startAnimation();

在anim.startAnimation内部其实就是调用了handler.mAnimations.add();将当前动画加入到animationHandler的mAnimations集合中

然后将animationHandler的anim,加入到mTmpAnimations中,然后依此调用anim.doAnimationFrame方法,如果返回true,则将该动画加入到结束动画结合中。

循环调用mEndingAnims,mEndingAnims.get(i).endAnimation(this);内部,会将动画移除mAnimations,回调动画监听接口onAnimationEnd;以及重置各种标志变量。

如果mAnimations不为null,则再次调用scheduleAnimation();

3、总结

ofInt中实例化了一个ObjectAnimator对象,然后设置了target,propName,values(PropertyValuesHolder) ;然后分别在setInterpolator,setDuration设置了Interpolator

和duration。其中setEvaluator是给PropertyValuesHolder,以及keyframeSet设置估值算法。

PropertyValueHolder实际上是IntPropertyValueHolder类型对象,包含propName,valueType,keyframeSet .

keyframeset中存了Keyframe集合,keyframe中存储了(fraction , valuetype , value , hasValue)。

在start()中:

首先,步骤1:更新动画各种状态,然后初步计算fraction为(currentTime - mStartTime) / mDuration;然后将这个fraction交给我们的插值器计算后得到新的fraction,再将新的fraction交给我们的估值算法,估值算法根据开始、结束、fraction得到当前属性(动画作用的属性)应该的值,最大调用反射进行设置;

当然了:start中还会根据动画的状态,如果没有结束,不断的调用scheduleAnimation();该方法内部利用mChoreographer不断的去重复我们的上述步骤1。

猜你喜欢

转载自blog.csdn.net/u013928412/article/details/82557925