ObjectAnimator源码分析

224 阅读3分钟

如果文章有问题,请及时指出

文中源码都来自android28

整体流程

ObjectAnimator.start()

-> ValueAnimator.start()

-> ValueAnimator.addAnimationCallback()

-> AnimationHandler.addAnimationFrameCallback()

-> MyFrameCallbackProvider.postFrameCallback()

-> Choreographer.postFrameCallback(callback); // 请求Vsync信号
// Vsync信号到了
-> Choreographer.doFrame()

-> Choreographer.doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

-> AnimationHandler.doAnimationFrame()

-> ValueAnimator.doAnimationFrame()

-> ValueAnimator.animateBasedOnTime()

-> ObjectAnimator.animateValue()

-> valueAnimator.animateValue(currentIterationFraction) // 使用插值器计算属性值变化比例(百分比)

  -> PropertyValuesHolder.calculateValue(fraction) // 使用估值器计算最终值
  -> AnimatorUpdateListener.onAnimationUpdate(this) // 通知监听更新值

-> PropertyValuesHolder.setAnimatedValue(target) // 使用seter修改属性值

插值器:

插值器其实是变化快慢的一个衡量标准,根据时间流逝的比例,来得出属性变化的比例。可能返回小于0或者大于1的值。

当前时间流逝百分比 -> 当前属性变化的比例 控制变化速率

估值器:

属性变化的比例 -> 动画当前具体值 计算具体值

ObjectAnimator

ObjectAnimator通过重写ValueAnimator中的animateValue()方法,修改属性值的。

void animateValue(float fraction) {
    final Object target = getTarget();
    if (mTarget != null && target == null) {
        // We lost the target reference, cancel and clean up. Note: we allow null target if the
        /// target has never been set.
        cancel();
        return;
    }

    super.animateValue(fraction);
    int numValues = mValues.length;
    for (int i = 0; i < numValues; ++i) {
        // 修改属性值
        mValues[i].setAnimatedValue(target);
    }
}

ValueAnimator

ValueAnimator.java 

PropertyValuesHolder[] mValues; // 记录属性名,会反射调用修改属性值 
private void start(boolean playBackwards) {
    ......
    // 会请求Choreographer 
    addAnimationCallback(0); 
    ......
}


private void addAnimationCallback(long delay) {
    if (!mSelfPulse) {
        return;
    }
    getAnimationHandler().addAnimationFrameCallback(this, delay);
}


// Choreographer垂直同步信号到时,会调用这个方法 
public final boolean doAnimationFrame(long frameTime) { 
    ..... 
    // 计算动画数值 
    boolean finished = animateBasedOnTime(currentTime); 
    ..... 
} 

boolean animateBasedOnTime(long currentTime) { 
    ....... 
    animateValue(currentIterationFraction);
    ....... 
} 

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


AnimationHandler

与Choreographer通信,请求Vsync信号

AnimationHandler.java

private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
    @Override
    public void doFrame(long frameTimeNanos) {
        // 执行当前帧动画
        doAnimationFrame(getProvider().getFrameTime());
        if (mAnimationCallbacks.size() > 0) {
            // 请求下一个Vsync
            getProvider().postFrameCallback(this);
        }
    }
};


PropertyValuesHolder

PropertyValuesHolder保存属性名称,拥有set方法(用于反射),通过Keyframes使用估值器计算值。

PropertyValuesHolder.java 

String mPropertyName;// 属性名称 例如translationX、scaleX、alpha等 

Method mSetter = null; // 属性的set方法 

private TypeEvaluator mEvaluator; // 估值器 

Keyframes mKeyframes = null; // 计算时间和数值关系的,给定时间,返回动画值的。使用估值器计算。 

void calculateValue(float fraction) { 
    // 根据进度使用估值器计算具体值 
    Object value = mKeyframes.getValue(fraction); 
    mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}

Keyframe

Keyframe关键帧:

  • fraction:表示当前的属性值变化百分比;

  • value:表示当前应该在的位置 

KeyframeSet:关键帧集合。

public class KeyframeSet implements Keyframes 

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]为0 
        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) { 
            // 关键帧的Keyframe.fraction(属性值变化百分比)是等分的。 
            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); 
}

以FloatKeyframeSet为例。

class FloatKeyframeSet extends KeyframeSet implements Keyframes.FloatKeyframes { 

@Override public float getFloatValue(float fraction) { 
    if (fraction <= 0f) { ..... return xxxx } 
    else if (fraction >= 1f) { ....... return xxxx } 
    // fraction 在(0, 1) 
    FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
    for (int i = 1; i < mNumKeyframes; ++i) { 
        FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i); 
        // 找到fraction 所在 [prevKeyframe, nextKeyframe] 
        if (fraction < nextKeyframe.getFraction()) {
            final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); 
            // 把fraction换算到 [preKeyframe, nextKeyframe] 间变化率 
            // 后续例子,比如:fraction=0.2,应该在[0.1,0.2]关键帧之间, (0.2 - 0)/ (0.25 - 0) = 0.8 
            // intervalFraction = 0.8,就是在[0.1, 0.2]关键帧区间的属性值变化率 
            float intervalFraction = (fraction - prevKeyframe.getFraction()) / (nextKeyframe.getFraction() - prevKeyframe.getFraction());
            float prevValue = prevKeyframe.getFloatValue(); 
            float nextValue = nextKeyframe.getFloatValue(); 
            // Apply interpolator on the proportional duration. 
            if (interpolator != null) { 
                intervalFraction = interpolator.getInterpolation(intervalFraction); 
            } 
            return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). floatValue(); 
        } 
        prevKeyframe = nextKeyframe;
    } 
    // shouldn't get here 
    return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue(); 
}

Keyframe就是动画初始化时设置的属性值,每设置一个值,表示一个Keyframes对象。每个动画至少2个Keyframe(表示开始和结束)。

动画设置多个值(也能控制属性变化率的),就有多个关键帧。

如下例子,每个关键帧都等分属性变化比。设置了5个值,会把动画属性变化比等分4份,每份1/4,0.1是起始值,属性变化比[0,0.25] 在值[0.1, 0.2]之间变化;属性变化比[0.25,0.5] 在值[0.2,0.3]之间变化。

ObjectAnimator.ofFloat(mImage1, "scaleY", 0.1, 0.2, 0.3, 0.5, 1)

自己设置关键帧的参数。

Keyframe keyframe1 = Keyframe.ofFloat(0,0); 
Keyframe keyframe2 = Keyframe.ofFloat(0.2f,200); 
Keyframe keyframe3 = Keyframe.ofFloat(0.7f,100); 
Keyframe keyframe4 = Keyframe.ofFloat(1,300); 
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3,keyframe4); 
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageView,holder);