属性动画原理

属性动画原理

相关类

ObjectAnimator 和 ValueAnimator 及区别

  1. ValueAnimator 类是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作
  2. ObjectAnimator 类是先改变值,然后 自动赋值 给对象的属性 (反射调用对象的 setter 方法,还是需要手动 invalidate() 等操作的) 从而实现动画;是 直接 对对象属性进行操作;

Property

public abstract class Property<T, V> {
    private final String mName;
    private final Class<V> mType;
    public static <T, V> Property<T, V> of(Class<T> hostType, Class<V> valueType, String name) {
        return new ReflectiveProperty<T, V>(hostType, valueType, name);
    }
    public Property(Class<V> type, String name) {
        mName = name;
        mType = type;
    }
    public boolean isReadOnly() {
        return false;
    }
    public void set(T object, V value) {
        throw new UnsupportedOperationException("Property " + getName() +" is read-only");
    }
    public abstract V get(T object);
    public String getName() {
        return mName;
    }
    public Class<V> getType() {
        return mType;
    }
}
  1. set 方法的参数和 get 方法的返回值同一个 T 类型
  2. 在属性动画中,set 用于更新动画需要的值,动画更新(如调用 invalidate())
  3. 在属性动画中,get 用于使用者获取没有提供初始值
  4. 提供可包装三方 view 未能正确的实现 setter/getter 方法来实现 ObjectAnimator 属性动画

PropertyValuesHolder setter/getter; 计算值; 更新值

PropertyValuesHolder 作用

  1. 持有 Property 用于获取动画初始化值 get, 更新动画值 set;持有 mPropertyName 通过反射获取 getter/setter 方法,获取初始值和更新动画值
  2. 计算动画过程中的值(calculateValue),根据 fraction,具体通过 Keyframes.getValue()(int/float 是 IntKeyframesSet/FloatKeyFramesSet)
  3. 更新动画过程中的值(setAnimatedValue),调用 Property 的 set 或者 target.propertyName 的 setter 方法更新值
  4. 所有的属性动画的 value 都转化成 PropertyValuesHolder 来操作
public class PropertyValuesHolder {
    // int类型默认估值器
    private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
    // float类型默认估值器
    private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
    
    String mPropertyName; // ofXXX传递进来的
    protected Property mProperty; // ofXXX传递进来的
    Method mSetter = null;
    private Method mGetter = null;
    Class mValueType;
    Keyframes mKeyframes = null;
    private TypeEvaluator mEvaluator;
    private Object mAnimatedValue;
    private TypeConverter mConverter;

    private PropertyValuesHolder(String propertyName) {
        mPropertyName = propertyName;
    }
    private PropertyValuesHolder(Property property) {
        mProperty = property;
        if (property != null) {
            mPropertyName = property.getName();
        }
    }
    public static PropertyValuesHolder ofInt(String propertyName, int... values) {
        return new IntPropertyValuesHolder(propertyName, values);
    }
    public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values) {
        return new IntPropertyValuesHolder(property, values);
    }
    
    // 反射获取getXXX方法(mPropertyName的首字母大写前加get,如foo,getFoo);如果有mConverter那么从mConverter中获取,否则从mValueType中获取
    private void setupGetter(Class targetClass) {
        mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
    }
    
    // 反射获取setXXX方法(mPropertyName的首字母大写前加set,如foo,setFoo);如果有mConverter那么从mConverter中获取,否则从mValueType中获取
    void setupSetter(Class targetClass) {
        Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
    }
    
    // 在ValueAnimator.startAnimation调用 → ObjectAnimator重写initAnimation调用(在ValueAnimator的initAnimation不会调用setupSetterAndGetter)
    void setupSetterAndGetter(Object target) {
        if (mProperty != null) { // mProperty不为null
            try {
                Object testValue = null;
                List<Keyframe> keyframes = mKeyframes.getKeyframes(); // mKeyframes在ofXXX已经赋值了
                int keyframeCount = keyframes == null ? 0 : keyframes.size();
                for (int i = 0; i < keyframeCount; i++) {
                    Keyframe kf = keyframes.get(i);
                    if (!kf.hasValue() || kf.valueWasSetOnStart()) { // 未设置初始值(ofXXX只提供了一个值,Keyframe只有一个参数的构造方法) 或 设置了从gettter中获取值(这里是Propery.get)
                        if (testValue == null) {
                            testValue = convertBack(mProperty.get(target));
                        }
                        kf.setValue(testValue);
                        kf.setValueWasSetOnStart(true);
                    }
                }
                return;
            } catch (ClassCastException e) { // Property和target类型对应不上
                Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +
                        ") on target object " + target + ". Trying reflection instead");
                mProperty = null;
            }
        }
        // 没有写else是因为mProperty可能和target类型对应不上
        if (mProperty == null) { // mProperty为null或mProperty可能和target类型对应不上被置为null了
            Class targetClass = target.getClass();
            if (mSetter == null) {
                setupSetter(targetClass);  // 注册setter
            }
            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()) { // 未设置初始值(ofXXX只提供了一个值,Keyframe只有一个参数的构造方法) 或 设置了从gettter中获取值
                    if (mGetter == null) {
                        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());
                    }
                }
            }
        }
    }
    
    // 根据当前动画进度fraction计算具体的动画值;在ValueAnimator#animateValue调用
    void calculateValue(float fraction) {
        Object value = mKeyframes.getValue(fraction); // 调用Keyframes#getValue计算出具体的动画值
        mAnimatedValue = mConverter == null ? value : mConverter.convert(value); // 如果设置了mConverter,转换下
    }
    
    // 更新值,在ObjectAnimator#animateValue中调用(animateValue是在ValueAnimator接受到时钟脉冲信号回调调用);mProperty和mSetter一般是互斥的,2种逻辑只会选择一种
    void setAnimatedValue(Object target) {
        if (mProperty != null) { // mProperty不为null,调用set更新值
            mProperty.set(target, getAnimatedValue());
        }
        if (mSetter != null) {
            try {
                mTmpValueArray[0] = getAnimatedValue();
                mSetter.invoke(target, mTmpValueArray);
            } catch (InvocationTargetException e) {
                Log.e("PropertyValuesHolder", e.toString());
            } catch (IllegalAccessException e) {
                Log.e("PropertyValuesHolder", e.toString());
            }
        }
    }
    
    
    // ValueAnimator.initAnimation调用;自动处理Integer和Float的估值器,int和float不会走到这里,分别走IntKeyframeSet和FloatKeyframeSet
    void init() {
        if (mEvaluator == null) {
            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : (mValueType == Float.class) ? sFloatEvaluator : null;
        }
        if (mEvaluator != null) {
            mKeyframes.setEvaluator(mEvaluator);
        }
    }
}
  1. init ValueAnimator.initAnimation 调用;自动处理 Integer 和 Float 的估值器,int 和 float 不会走到这里,分别走 IntKeyframeSet 和 FloatKeyframeSet
  2. setupSetterAndGetter 通过反射获取属性的 get set 方法或 Property 的 set/get 设置初始值(当然 一些 PropertyValuesHolder 的子类重载使用了 jni 方法获得反射方法。其实都是目的都是一样。)
  3. 更新值,先通过 calculateValue 计算出动画需要的值,再通过 setAnimatedValue 调用 Property#set 或反射 target 的 setter 更新值

Keyframe/Keyframes/KeyframeSet

关键帧的作用:

  1. 关键帧 keyframe 用于保存动画的每一个关键数据帧,个数由传入的 value 个数决定,系数 fraction 由 value 传入顺序决定。
  2. 保存每个关键帧的 fraction
  3. 通过动画类传入的 fraction,利用估值器计算出 真正的属性值。

Keyframe 关键帧

记录关键帧数据,他默认有三个实现类 IntKeyframeFloatKeyframeObjectKeyframe,当然我们也能继承 Keyframe 实现自己的关键帧类型。不过大部分情况,提供的这三种方式已经够用了。

Keyframe 有三个重要的属性值:

  1. mHasValue 用于记录关键帧是否初始化了值,以 子类 IntKeyframe 为例,它有两个构造方法:
// Keyframe#IntKeyframe Android29
static class IntKeyframe extends Keyframe {
    /**
     * The value of the animation at the time mFraction.
     */
    int mValue;
    
    IntKeyframe(float fraction, int value) { // #1
        mFraction = fraction;
        mValue = value;
        mValueType = int.class;
        mHasValue = true;
    }
    
    IntKeyframe(float fraction) { // #2
        mFraction = fraction;
        mValueType = int.class;
    }
}

第一个构造方法 (1) 初始化了 mValue ,同时 mHasValue 会标记 为 true;第二个构造方法 (2) 只初始化了 mFraction,并未给 mValue 赋值,默认 mHasValue 为 false;假如我们使用了 mHasValue 为 false 的关键帧。那么在动画初始化时会调用 PropertyValuesHolder.setupSetterAndGetter 给每一个关键帧赋初始值。

  1. mFraction 记录该关键帧所有关键帧中的位置,float 类型,值范围 0 - 1
  2. mValue 记录 value 值,当然不同类型的 Keyframe value 值类型也不同,所以 mValue 由子类实现

Keyframes 一堆 Keyframe 组成的集合

它的实现类有 KeyframeSetPathKeyframes,它的子接口有 IntKeyframesFloatKeyframes

// Keyframes Android29
public interface Keyframes {
    // 估值器,计算动画值时用;不是IntKeyframes和FloatKeyframes需要设置估值器
    void setEvaluator(TypeEvaluator evaluator);
    Class getType();
    // 获取动画值;随着动画的完成度,interpolator和evaluator计算出出来的真正的动画值
    Object getValue(float fraction);
    List<Keyframe> getKeyframes();
}
KeyframeSet

两个子类 IntKeyframeSet、FloatKeyframeSet,分别实现了对应的 IntKeyframes 和 FloatKeyframes 接口。

ofInt 用的是 IntKeyframeSet,float 用的是 FloatKeyframeSet

// KeyframeSet Android29
public class KeyframeSet implements Keyframes {
    int mNumKeyframes; // 关键帧数量

    Keyframe mFirstKeyframe; // 第一帧
    Keyframe mLastKeyframe; // 最后一帧
    TimeInterpolator mInterpolator; // only used in the 2-keyframe case;插值器,只有数量2的关键帧用这个TimeInterpolator
    List<Keyframe> mKeyframes; // only used when there are not 2 keyframes,不是数量2关键帧
    TypeEvaluator mEvaluator; // 估值器
    
    public KeyframeSet(Keyframe... keyframes) {
        mNumKeyframes = keyframes.length;
        // immutable list
        mKeyframes = Arrays.asList(keyframes);
        mFirstKeyframe = keyframes[0];
        mLastKeyframe = keyframes[mNumKeyframes - 1];
        mInterpolator = mLastKeyframe.getInterpolator();
    }
    
    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);
    }
    // ofFloat
    // ofKeyframe
    // ofObject
    // ofPath
    
    public Object getValue(float fraction) {
        // Special-case optimization for the common case of only two keyframes
        if (mNumKeyframes == 2) { // 关键帧数量为2 
            if (mInterpolator != null) {
                fraction = mInterpolator.getInterpolation(fraction); // 插值器计算出fraction
            }
            return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
                    mLastKeyframe.getValue()); // 估值器算出真正的动画值
        }
        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;
        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();
    }
}

Keyframes 最核心的方法是 getValue 方法。

  1. 仅有两个关键帧时,只有在这种情况下才使用 mInterpolator- 插值器。通过插值器 得到修正后的系数 fraction,然后拿这个系数,通过估值器 mEvaluator 计算出属性值
  2. if (fraction <= 0f) 和 if (fraction >= 1f) 这两个分支是特殊情况,出现在动画第一帧和最后一帧的情况
  3. 正常动画中的分支,通过 fraction 查找符合 fraction < nextKeyframe.getFraction() 的第一帧,然后计算 fraction 在前一帧到当前帧范围内的位置。

例如查找到符合条件的当前帧 fraction =0.5; 前一帧 fraction = 0.2, 动画当前的 fraction =0.3,那么新的 intervalFraction = 1/3f。然后拿着这个值给估值器计算属性值。

TimeInterpolator 插值器

插值器,定义了动画的变化速率 (消逝到篡改的一个映射),允许动画有非线性的变化,如加速、减速

// TimeInterpolator Android29
public interface TimeInterpolator {
    // elapsed fraction(消逝的部分)和 interpolated fraction(篡改的部分)的一个映射
    float getInterpolation(float input); 
    // 参数input,[0~1],0表示开始,1表示结束
    // 返回值,可能大于1表示overshoot,小于0表示undershoot
}

TypeEvaluator 估值器

估值器,动画变化过程中根据当前进度 fraction 计算出的做动画的实际值

public interface TypeEvaluator<T> { 
   public T evaluate(float fraction, T startValue, T endValue);
   // 参数fraction 当前动画进度
   // 参数startValue 开始值
   // 参数endValue 结束值
   
   // 返回值 简单的计算公式:result = startValue + fraction * (endValue - startValue)
}

属性动画原理 以 ofInt 举例

动画的创建

常用的属性动画创建方法

ObjectAnimator.ofInt()
ObjectAnimator.ofFloat()
ObjectAnimator.ofArgb()
ObjectAnimator.ofObject()
ObjectAnimator.ofPropertyValuesHolder()

以一个常用的方法 ObjectAnimator.ofInt() 为切入点层层深入解析属性动画的创建过程。

早期版本的属性动画 ofInt 方法有两个实现,到 Android O 为止已经有 4 个实现了,主要就是增加了 Path 参数:

// ObjectAnimator Android29
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName); // #1
        anim.setIntValues(values); // #2
        return anim;
    }
public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
        ObjectAnimator anim = new ObjectAnimator(target, property); // #1
        anim.setIntValues(values);  // #2
        return anim;
    }

ofInt 方法的第一行 (propertyName1) 均是创建 ObjectAnimator 对象。但分别使用了两种构造方式 propertyName 和 Property。

ObjectAnimator 构造

// ObjectAnimator Android29
public ObjectAnimator() {}
private ObjectAnimator(Object target, String propertyName) {
    setTarget(target); #propertyName#1
    setPropertyName(propertyName); #propertyName#2
}
private <T> ObjectAnimator(T target, Property<T, ?> property) {
    setTarget(target); #Property#1
    setProperty(property); #Property#2
}

另外两个构造方法第一行代码都是 setTaret:

setTaret(Object)
private WeakReference<Object> mTarget;
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;
    }
}
setTarget(target);

mTarget 是记录需要做动画的对象的虚引用,方便以后调用该对象 getter/setter;如果 mTarget 不存在时,在 animateValue 会 cancel 当前动画。

setPropertyName/setProperty

propertyName2,setPropertyName(String)

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

mValues 肯定为 null,不会走 if 分支,赋值 mPropertyName;如果 mValues 不为空的情况下,会更新 mValues 的第一个元素的属性值,并更新对应的 map 集合

Property2,setProperty(Property)

public void setProperty(@NonNull Property property) {
    // 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.setProperty(property);
        mValuesMap.remove(oldName);
        mValuesMap.put(mPropertyName, valuesHolder);
    }
    if (mProperty != null) {
        mPropertyName = property.getName();
    }
    mProperty = property;
    // New property/values/target should cause re-initialization prior to starting
    mInitialized = false;
}

同 setPropertyName(String),mPropertyName 从 property.getName 获取,赋值 mProperty

现在看 anim.setIntValues(values);(#2):

// ObjectAnimator Android29
public void setIntValues(int... values) {
    if (mValues == null || mValues.length == 0) {
        if (mProperty != null) {
            setValues(PropertyValuesHolder.ofInt(mProperty, values));
        } else {
            setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
        }
    } else {
        super.setIntValues(values);
    }
}

第一次调用 mValues 为 null 走入 if 流程,假如我们调用的 propertyName 参数的方法,会执行 setValues(PropertyValuesHolder.ofInt(mPropertyName, values));,反之执行 setValues(PropertyValuesHolder.ofInt(mProperty, values));

我们先看看 PropertyValuesHolder.ofInt(mProperty/propertyName, values):

// PropertyValuesHolder Android29
public class PropertyValuesHolder {
    private PropertyValuesHolder(String propertyName) {
        mPropertyName = propertyName;
    }
    private PropertyValuesHolder(Property property) {
        mProperty = property;
        if (property != null) {
            mPropertyName = property.getName();
        }
    }
    public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values) {
        return new IntPropertyValuesHolder(property, values);
    }
    public static PropertyValuesHolder ofInt(String propertyName, int... values) {
        return new IntPropertyValuesHolder(propertyName, values);
    }
    public void setIntValues(int... values) {
        mValueType = int.class;
        mKeyframes = KeyframeSet.ofInt(values);
    }
}
static class IntPropertyValuesHolder extends PropertyValuesHolder {
    public IntPropertyValuesHolder(String propertyName, int... values) {
        super(propertyName);
        setIntValues(values);
    }
    public IntPropertyValuesHolder(Property property, int... values) {
        super(property);
        setIntValues(values);
        if (property instanceof  IntProperty) {
            mIntProperty = (IntProperty) mProperty;
        }
    }
    @Override
    public void setIntValues(int... values) {
        super.setIntValues(values);
        mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
    }
}

PropertyValuesHolder#ofInt,创建一个 IntPropertyValuesHolder,保存 propertyName/Property,调用 PropertyValuesHolder#setIntValues,生成关键帧 (keyframe)。

ofInt

现在回到 ObjectAnimator.ofInt,看看 setIntValues()

public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
    ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    anim.setIntValues(values);
    return anim;
}
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);
    }
    mInitialized = false;
}
public void setIntValues(int... values) {
    if (mValues == null || mValues.length == 0) {
        if (mProperty != null) {
            setValues(PropertyValuesHolder.ofInt(mProperty, values));
        } else {
            setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
        }
    } else {
        super.setIntValues(values);
    }
}

可以看到用 values 用单个 PropertyValuesHolder 包装了下,赋值给了 mValues

在上面 PropertyValuesHolder 知道 PropertyValuesHolder.ofInt 会生成关键帧 keyframes 信息

动画启动 start()

// ObjectAnimator Android29
public void start() {
    AnimationHandler.getInstance().autoCancelBasedOn(this);
    super.start();
}

// ValueAnimator Android29
public void start() {
    start(false);
}
private void start(boolean playBackwards) {
    mReversing = playBackwards;
    // 动画的状态
    mStarted = true;
    mPaused = false;
    mRunning = false;
    // ... 
    addAnimationCallback(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) { // mSeekFraction为负数,没有seek,从0开始
            // 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); // 最终也是调用的setCurrentFraction
        } else {
            setCurrentFraction(mSeekFraction);
        }
    }
}
public void setCurrentFraction(float fraction) { // 
    initAnimation();
    fraction = clampFraction(fraction);
    // ...
    mOverallFraction = fraction;
    final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
    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); // 通知AnimatorUpdateListener值更新了
        }
    }
}

如果是 ObjectAnimator,AnimationHandler.getInstance().autoCancelBasedOn(this) 会 cancel 相同 Target 和相同属性的动画,AnimationHandler 实例在线程局部单例。autoCancelBasedOn(this) 会遍历 AnimationHandler 实例持有的所有未完成的 ValueAnimator 实例,cancel 掉符合条件的动画。

紧接着 super.start() 调用了 ValueAnimator.start()

private float clampFraction(float fraction) {
    if (fraction < 0) {
        fraction = 0;
    } else if (mRepeatCount != INFINITE) {
        fraction = Math.min(fraction, mRepeatCount + 1);
    }
    return fraction;
}

现在看 addAnimationCallback(this)

// ValueAnimator Android29
private void addAnimationCallback(long delay) {
    if (!mSelfPulse) {
        return;
    }
    getAnimationHandler().addAnimationFrameCallback(this, delay); // 如果dalay大于0,callback 会在delay 时间后的下一个frame获得回调
}
public AnimationHandler getAnimationHandler() {
    return AnimationHandler.getInstance();
}

通过 AnimationHandler 的 addAnimationFrameCallback 添加了个回调,AnimationHandler 是什么?

// AnimationHandler Android29
public class AnimationHandler {
    private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime()); // 处理当前帧
            if (mAnimationCallbacks.size() > 0) { // 如果当前当前未结束,mAnimationCallbacks>0的,继续注册下一帧的callback。为什么还要注册一次呢?之前不是注册过一次了吗?难道Choreographer把这个callback 释放了:是在Choreographer#recycleCallbackLocked(callbacks);来回收整个链表中的节点记录。
                getProvider().postFrameCallback(this);
            }
        }
    };
    public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>(); 
    public static AnimationHandler getInstance() { // 线程单例,即主线程都共享该实例,所有的属性动画都通过这个来处理
        if (sAnimatorHandler.get() == null) {
            sAnimatorHandler.set(new AnimationHandler());
        }
        return sAnimatorHandler.get();
    }
    
    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));
        }
    }
    
    private AnimationFrameCallbackProvider getProvider() {
        if (mProvider == null) {
            mProvider = new MyFrameCallbackProvider();
        }
        return mProvider;
    }
}

如果是首次 getProvider().postFrameCallback(mFrameCallback);,getProvider() 是啥?

// AnimatorHandler Android29
private AnimationFrameCallbackProvider getProvider() {
    if (mProvider == null) {
        mProvider = new MyFrameCallbackProvider();
    }
    return mProvider;
}

创建了一个 MyFrameCallbackProvider 实例,MyFrameCallbackProvider 继承 AnimationFrameCallbackProvider

// AnimatorHandler Android29
public interface AnimationFrameCallbackProvider {
    void postFrameCallback(Choreographer.FrameCallback callback);
    void postCommitCallback(Runnable runnable);
    long getFrameTime();
    long getFrameDelay();
    void setFrameDelay(long delay);
}

AnimationFrameCallbackProvider 接口定义了一些回调接口,按照注释说明主要作用是 提高 ValueAnimator 的可测性,通过这个接口隔离,我们可以自定义 定时脉冲,而不用使用系统默认的 Choreographer,这样我们可以在测试中使用任意的时间间隔的定时脉冲.既然可以方便测试,那肯定有 API 来更改 Provider:那就是 setProvider。

// AnimatorHandler Android29
public void setProvider(AnimationFrameCallbackProvider provider) {
    if (provider == null) {
       mProvider = new MyFrameCallbackProvider();
    } else {
       mProvider = provider;
    }
}

ValueAnimator 提供了一个 setProvider 通过自定义的 Provider 提供我们想要的任意时间间隔的回调,来更新动画。

最终走的是 MyFrameCallbackProviderpostFrameCallback(),现在我们看看 MyFrameCallbackProvider 是什么?

// MyFrameCallbackProvider Android29
private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {

    final Choreographer mChoreographer = Choreographer.getInstance();

    @Override
    public void postFrameCallback(Choreographer.FrameCallback callback) {
        mChoreographer.postFrameCallback(callback);
    }

    @Override
    public void postCommitCallback(Runnable runnable) {
        mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
    }

    @Override
    public long getFrameTime() {
        return mChoreographer.getFrameTime();
    }

    @Override
    public long getFrameDelay() {
        return Choreographer.getFrameDelay();
    }

    @Override
    public void setFrameDelay(long delay) {
        Choreographer.setFrameDelay(delay);
    }
}

MyFrameCallbackProvider.postFrameCallback() 调用了 Choreographer.postFrameCallback(),使用 vsync(垂直同步)来协调 View 的绘制和动画的执行间隔。最终回调到 AnimationFrameCallbackboolean doAnimationFrame(long frameTime); 方法,frameTime 的时间是 SystemClock#uptimeMillis(),返回 true 动画结束。

系统默认使用的 Choreographer 做定时脉冲来协调 frame 的更新;Choreographer 实例也是线程局部单例的。

现在我们又回到了 ValueAnimator 的 doAnimationFrame 方法:

// ValueAnimator Android29
// 处理一帧的动画,frameTime,当前帧的SystemClock#uptimeMillis()时间
public final void doAnimationFrame(long frameTime) {
   AnimationHandler handler = AnimationHandler.getInstance();
   if (mLastFrameTime == 0) {
       // First frame
       //如果是动画的第一次回调,注册调整到下一个 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);
   }
   // ... comments
   final long currentTime = Math.max(frameTime, mStartTime);
   boolean finished = animateBasedOnTime(currentTime); // 返回值finished标记是否动画已经执行完毕。如果最后一个关键帧(Keyframe)执行完毕,这里返回true,会执行endAnimation()做一些状态位复位和动画结束回调等等。
   if (finished) {
       endAnimation();
   }
}

frameTime 是当前 frame 时间,调用 animateBasedOnTime(currentTime)

boolean animateBasedOnTime(long currentTime) {
   boolean done = false;
   if (mRunning) {
       final long scaledDuration = getScaledDuration(); // 默认不scale,调用overrideDurationScale(float durationScale)进行设置scale
       final float fraction = scaledDuration > 0 ?
                    (float)(currentTime - mStartTime) / scaledDuration : 1f;
       final float lastFraction = mOverallFraction;
       final boolean newIteration = (int) fraction > (int) lastFraction;
       final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
                    (mRepeatCount != INFINITE);
       if (scaledDuration == 0) {
           // 0 duration animator, ignore the repeat count and skip to the end
           done = true;
       } else if (newIteration && !lastIterationFinished) {
          // Time to repeat
          if (mListeners != null) {
              int numListeners = mListeners.size();
              for (int i = 0; i < numListeners; ++i) {
                   mListeners.get(i).onAnimationRepeat(this);
              }
           }
       } else if (lastIterationFinished) {
           done = true;
       }
       mOverallFraction = clampFraction(fraction);
       float currentIterationFraction = getCurrentIterationFraction(mOverallFraction);
       animateValue(currentIterationFraction);
   }
   return done;
}
  1. currentTime 是 Choreographer 发出的计时脉冲时间,纳秒计时。
  2. fraction 根据 currentTime 计算 fraction(currentTime-mStartTime/duration) 系数,即动画时间流逝比。
  3. 然后执行 ValueAnimator#animateValue(currentIterationFraction) 计算动画的在当前时间比例下属性动画的值;如果是 ObjectAnimator 还会降属性值设置该 Target。animateValue 方法被 ObjectAnimator 重载了。

ValueAnimator#animateValue

// ValueAnimator Android29
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);
        }
    }
}
  1. 参数 fraction 这个时间流逝比系数是线性的。通过 mInterpolator.getInterpolation() 计算出我们想要的 fraction;
  2. 从前面可以知道 mValues 是 PropertyValuesHolder,遍历所有的 PropertyValuesHolder.calculateValue(fraction) 使用这个系数 fraction 计算出 mAnimatedValue,从前面的 PropertyValuesHolder 分析可以知道,最终是通过 Keyframes#getValue,估值器计算最终的动画值(如果是 int 为 IntKeyframeSet)。
  3. 最后 mUpdateListeners#onAnimationUpdate 通知更新

ObjectAnimator#animateValue

如果是 ObjectAnimator,重写了 animateValue 方法

// ObjectAnimator Android29
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);
    }
}

// PropertyValuesHolder Android29
void setAnimatedValue(Object target) {
   if (mProperty != null) {
       mProperty.set(target, getAnimatedValue());
   }
   if (mSetter != null) {
     mTmpValueArray[0] = getAnimatedValue();
     mSetter.invoke(target, mTmpValueArray);
  }
}

可以看到 ObjectAnimator 相比较于 ValueAnimator,调用了 ValueAnimator 的 animateValue 计算动画值和通知更新后,还调用了 PropertyValuesHolder#setAnimatedValue 更新到对应 target 的属性值 (调用 Property 的 set 或反射 target 的 setter 方法)

总结

  1. ObjectAnimator#autoCancelBasedOn:相同属性,相同 target 的动画,防止出现多个动画同时更新 Target 的属性,出现错乱。不过这一行为默认是关闭的,设置 ObjectAnimator.setAutoCancel(true) 来打开
  2. AnimationHandler.addAnimationFrameCallback 向 Choreographer 注册 Choreographer.FrameCallback 回调,通过该回调获得渲染时间脉冲的回调;通过系统的 vsync 垂直同步信号来协调 cpu,gpu 和渲染的时序;Choreographer 获得 vsync 信号后 根据 当前帧的纳秒来查找哪些 Choreographer.FrameCallback 会被执行。
  3. 执行 AnimationHandler.doAnimationFrame() 方法,开始真正的动画逻辑。
  4. ValueAnimator.animateBasedOnTime(time) 执行,通过 TimeInterpolator 计算最终的 时间流逝比 fraction,然后调用 PropertyValuesHolder.calculateValue(fraction) 计算属性的值,并回调 AnimatorUpdateListener.onAnimationUpdate() 方法。
  5. PropertyValuesHolder 调用 Keyframes.getIntValue(fraction),这中间又使用到估值器 TypeEvaluator 和 Keyframe 最终结算处我们需要的属性值。
  6. 然后 ObjectAnimator 调用 PropertyValuesHolder.setAnimatedValue(target) 来更新 target 的属性值。

Ref