- 属性动画的集成关系
- 看一段属性动画的使用代码
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<Keyframe> 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); } } }
- 上面我们看到 addAnimationFrameCallback()中传递了一个this 说明ValueAnimator也实现了该接口 且是循环的不断调用该抽象回调方法
果然实现了该接口 我们去看看该接口有什么抽象方法 -
//该抽象方法有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<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; } } // 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<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) { 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<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); } 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()