属性动画(ObjectAnimator)源码分析

属性动画的集成关系

Paste_Image.png
看一段属性动画的使用代码
ObjectAnimator animator=ObjectAnimator.ofFloat(image,"rotationX",0f,360f);
     animator.setDuration(2000);//执行时间
     animator.setInterpolator(new LinearInterpolator());//插值器
     animator.setRepeatCount(-1);//-1 代表无限循环执行
     animator.start();
跟进ObjectAnimator.ofFloat(image,"rotationX",0f,360f)
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
     ObjectAnimator anim = new ObjectAnimator(target, propertyName);
     anim.setFloatValues(values);
     return anim;
 }
继续进入anim.setFloatValues(values);
@Override
 public 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
         if (mProperty != null) {
             setValues(PropertyValuesHolder.ofFloat(mProperty, values));
         } else {
             setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
         }
     } else {
         super.setFloatValues(values);
     }
 }

进入PropertyValuesHolder.ofFloat(mPropertyName, values)

public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
     return new FloatPropertyValuesHolder(propertyName, values);
 }

这里出现了 PropertyValuesHolder 那么这个类是干嘛的呢?

PropertyValuesHolder:顾名思义,就是属性值持有者,它保存了动画过程中所需要操作的属性和对应的值,我们通过ofFloat(Object target, String propertyName, float… values)构造的动画,ofFloat()的内部实现其实就是将传进来的参数封装成PropertyValuesHolder实例来保存动画状态。在封装成PropertyValuesHolder实例以后,后面的操作也是以PropertyValuesHolder为主的

我们看到返回一个new FloatPropertyValuesHolder(propertyName, values) 进入构造方法

     public FloatPropertyValuesHolder(String propertyName, float... values) {
         super(propertyName);
         setFloatValues(values);
     }
//进入  super(propertyName) 看到只是跟PropertyValuesHolder的成员变量赋值
private PropertyValuesHolder(String propertyName) {
     mPropertyName = propertyName;
 }

进入 setFloatValues(values)

@Override
     public void setFloatValues(float... values) {
         super.setFloatValues(values);
         mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
     }
//进入super.setFloatValues(values);
public void setFloatValues(float... values) {
     mValueType = float.class;
     mKeyframes = KeyframeSet.ofFloat(values);
 }

KeyframeSet.ofFloat(values);
Keyframe:意为关键帧,设置了关键帧后,动画就可以在各个关键帧之间平滑过渡的,一个关键帧必须包含两个原素,第一时间点,第二位置,即这个关键帧是表示的是某个物体在哪个时间点应该在哪个位置上。fraction表示当前进度,value表示当前位置。

我们进入KeyframeSet.ofFloat(values)

public static KeyframeSet ofFloat(float... values) {
//这里的values 参数就是我们所传递动画执行参数比如:
//ObjectAnimator.ofFloat(image,"rotationX",0f,360f);中的0f ,360f
     boolean badValue = false;
     int numKeyframes = values.length;
//生成最小2个长度大小的数组
     FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
//单我们传递的参数只有一个的时候
     if (numKeyframes == 1) {
       //设置默认数组的元素的一个为0f
         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");
     }
     //将生成的数组添加到List集合
     return new FloatKeyframeSet(keyframes);
 }

接上一步进入new FloatKeyframeSet(keyframes);构造函数

public FloatKeyframeSet(FloatKeyframe... keyframes) {
     super(keyframes);
 }
//在进入super(keyframes) 父类 KeyframeSet
class KeyframeSet implements Keyframes {
 int mNumKeyframes;
 Keyframe mFirstKeyframe;
 Keyframe mLastKeyframe;
 TimeInterpolator mInterpolator; // only used in the 2-keyframe case
 List mKeyframes; // only used when there are not 2 keyframes
 TypeEvaluator mEvaluator;
 public KeyframeSet(Keyframe... keyframes) {
     mNumKeyframes = keyframes.length;
     // 将数组添加mKeyframes集合中 里面保存的是动画每的一帧
     mKeyframes = Arrays.asList(keyframes);
     mFirstKeyframe = keyframes[0];
     mLastKeyframe = keyframes[mNumKeyframes - 1];
     mInterpolator = mLastKeyframe.getInterpolator();
 }

由上可以看出:
PropertyValuesHolder 它保存了动画过程中所需要操作的属性和对应的值 同时持有KeyframeSet.ofFloat(values)得到动画每一帧的集合

我去再去属性动画的其他属性设置看看

//设置执行时间
@Override
@NonNull
public ObjectAnimator setDuration(long duration) {
    super.setDuration(duration);
    return this;
}
//进入super.setDuration(duration);
@Override
public ValueAnimator setDuration(long duration) {
    if (duration < 0) {
        throw new IllegalArgumentException("Animators cannot have negative duration: " +
                duration);
    }
    mUnscaledDuration = duration;
    updateScaledDuration();
    return this;
}
//设置执行时间 函数 sDurationScale=1.0f
private void updateScaledDuration() {
    mDuration = (long)(mUnscaledDuration * sDurationScale);
}
//设置插值器
@Override
public void setInterpolator(TimeInterpolator value) {
    if (value != null) {
        mInterpolator = value;
    } else {
      //如果为空 就使用默认的插值器 线性
        mInterpolator = new LinearInterpolator();
    }
}

最后我们来关注重点 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();
}
**super.start();**调用父类的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");
    }
    mReversing = playBackwards;
    // 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;
    // 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;
    AnimationHandler animationHandler = AnimationHandler.getInstance();
    //这里每隔16毫秒会回调一次该回调方法 这里有一个this 
    animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));

    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.
            setCurrentPlayTime(0);
        } else {
            setCurrentFraction(mSeekFraction);
        }
    }
}

Paste_Image.png
上面我们看到 addAnimationFrameCallback()中传递了一个this 说明ValueAnimator也实现了该接口 且是循环的不断调用该抽象回调方法

Paste_Image.png

果然实现了该接口 我们去看看该接口有什么抽象方法
//该抽象方法有2个 
interface AnimationFrameCallback {
    void doAnimationFrame(long frameTime);
    void commitAnimationFrame(long frameTime);
}
//抽象方法的实现
* Processes a frame of the animation, adjusting the start time if needed.
 *
 * @param frameTime The frame time.
 * @return true if the animation has ended.
 * @hide
 */
//参数为绘制一帧的时间(每隔16毫秒调用一次) 监听手机发出的Vsync信号 
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);
    }
    final long currentTime = Math.max(frameTime, mStartTime);
    boolean finished = animateBasedOnTime(currentTime);
    if (finished) {
        endAnimation();
    }
}
boolean finished = animateBasedOnTime(currentTime);将相对时间转换为绝对时间的百分比
boolean animateBasedOnTime(long currentTime) {
   boolean done = false;
   if (mRunning) {
       final long scaledDuration = getScaledDuration();
       //(总时间-开始时间)/运行的时间 得出运行百分比
       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) {
               //mListeners监听集合
               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);
       //这里调用ObjectAnimator子类的animateValue()函数
       animateValue(currentIterationFraction);
   }
   return done;
}

进入ObjectAnimator子类的animateValue()

@CallSuper
@Override
//参数执行百分比(0-1)
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) {
          //这里设置View的宽高 target代表动画控件
        mValues[i].setAnimatedValue(target);
    }
}
//进入父类的animateValue();
@CallSuper
void animateValue(float fraction) {
  //调用插值器的方法 (策略模式) 得到插值器运行百分比
    fraction = mInterpolator.getInterpolation(fraction);
  //赋值成员变量
    mCurrentFraction = fraction;
    int numValues = mValues.length;
    for (int i = 0; i < numValues; ++i) {
        //调用PropertyValuesHolder 的calculateValue();
        mValues[i].calculateValue(fraction);
    }
    if (mUpdateListeners != null) {
        int numListeners = mUpdateListeners.size();
        for (int i = 0; i < numListeners; ++i) {
          //动画更新监听回调回调
            mUpdateListeners.get(i).onAnimationUpdate(this);
        }
    }
}
//抽象插值器
public interface TimeInterpolator {
float getInterpolation(float input);
}
//PropertyValuesHolder 的calculateValue
void calculateValue(float fraction) {
    Object value = mKeyframes.getValue(fraction);
    //返回执行动画的百分比
    mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}
//接上面mAnimatedValue返回后回到 ObjectAnimator的 animateValue()继续执行来到
int numValues = mValues.length;
    for (int i = 0; i < numValues; ++i) {
          //这里设置View的宽高 target代表动画控件
        mValues[i].setAnimatedValue(target);
    }
//进入 mValues[i].setAnimatedValue(target);
void setAnimatedValue(Object target) {
    if (mProperty != null) {
        mProperty.set(target, getAnimatedValue());
    }
    if (mSetter != null) {
        try {
            mTmpValueArray[0] = getAnimatedValue();
            //mSetter是在startAnimator()初始化的时候通过反射赋值
            //invoke 重绘 动画view
            mSetter.invoke(target, mTmpValueArray);
        } catch (InvocationTargetException e) {
            Log.e("PropertyValuesHolder", e.toString());
        } catch (IllegalAccessException e) {
            Log.e("PropertyValuesHolder", e.toString());
        }
    }
}
//其中mSetter 是在动画初始化的时候赋值ObjectAnimator
@CallSuper
@Override
void 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();
    }
}
//其中mValues[i].setupSetterAndGetter(target); PropertyValuesHolder
void setupSetterAndGetter(Object target) {
    mKeyframes.invalidateCache();
    if (mProperty != null) {
        // check to make sure that mProperty is on the class of target
        try {
            Object testValue = null;
            List 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;
        }
    }
    // 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) {
            setupSetter(targetClass);
        }
        List 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) {
                    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());
                }
            }
        }
    }
}
其中: if (mSetter == null) {setupSetter(targetClass);}
private void setupGetter(Class targetClass) {
    mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
}
//继续深入
private Method setupSetterOrGetter(Class targetClass,
        HashMap> 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 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();
                propertyMapMap.put(targetClass, propertyMap);
            }
            propertyMap.put(mPropertyName, setterOrGetter);
        }
    }
    return setterOrGetter;
}
//其中: setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
    // TODO: faster implementation...
    Method returnVal = null;
    String methodName = getMethodName(prefix, mPropertyName);
    Class args[] = null;
    if (valueType == null) {
        try {
            //这里通过反射获取动画方法
            returnVal = targetClass.getMethod(methodName, args);
        } catch (NoSuchMethodException e) {
            // Swallow the error, log it later
        }
    } else {
        args = new Class[1];
        Class typeVariants[];
        if (valueType.equals(Float.class)) {
            typeVariants = FLOAT_VARIANTS;
        } else if (valueType.equals(Integer.class)) {
            typeVariants = INTEGER_VARIANTS;
        } else if (valueType.equals(Double.class)) {
            typeVariants = DOUBLE_VARIANTS;
        } else {
            typeVariants = new Class[1];
            typeVariants[0] = valueType;
        }
        for (Class typeVariant : typeVariants) {
            args[0] = typeVariant;
            try {
                returnVal = targetClass.getMethod(methodName, args);
                if (mConverter == null) {
                    // change the value type to suit
                    mValueType = typeVariant;
                }
                return returnVal;
            } catch (NoSuchMethodException e) {
                // Swallow the error and keep trying other variants
            }
        }
        // If we got here, then no appropriate function was found
    }

    if (returnVal == null) {
        Log.w("PropertyValuesHolder", "Method " +
                getMethodName(prefix, mPropertyName) + "() with type " + valueType +
                " not found on target class " + targetClass);
    }

    return returnVal;
}
属性动画的原理就是不断调用view.setScrollX() view.setScrollY()

你可能感兴趣的:(技术知识)