源码阅读_属性动画执行过程

本文详细解析了Android属性动画的执行过程,包括封装数据、注册垂直同步信号、初始化Setter方法以及往set方法中设置值的步骤。通过阅读源码,理解了ObjectAnimator的构造函数、setter方法的设置以及动画执行的内部逻辑,包括如何与UI线程同步和更新视图属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码阅读_属性动画执行过程

在Android开发中有很多地方使用到了属性动画,阅读源码是熟悉API以及相关代码最直接的方式。

在平时开发中使用属性动画最多的就是这类的代码

       val animator = ObjectAnimator.ofFloat(mView, "alpha", 0f, 100f, 50f)
       animator.duration = 1000
       animator.startDelay = 300
       animator.start()

封装数据

代码中第一句ObjectAnimator.ofFloat(…),直接打开源码(ObjectAnimator.java)

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
       ObjectAnimator anim = new ObjectAnimator(target, propertyName);
       anim.setFloatValues(values);
       return anim;
   }

在ofFloat方法中第一行代码是创建一个ObjectAnimator对象,构造函数中传入执行动画的View,以及属性名。

private ObjectAnimator(Object target, String propertyName) {
        setTarget(target);
        setPropertyName(propertyName);
    }

打开构造函数的代码,可以看到函数中又调用两个方法,看意思感觉挺明显一个是设置View,一个是设置属性名。

还是看一下setTarget方法和setPropertyName方法具体执行了什么逻辑

setTarget方法中,

  1. 先获取mTarget,判断获取的mTarget和目标View是否是同一个控件,很明显之前没有设置过mTarget,所以if (oldTarget != target)为true;
  2. 判断动画状态,如果是开始执行动画了就取消;
  3. 将目标View保存到全局变量mTarget中。
private WeakReference<Object> mTarget;

public Object getTarget() {
        return mTarget == null ? null : mTarget.get();
}

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

setPropertyName方法中

  1. 判断mValues是否为空;(第一次一定为空, 如果不为空,则用当前值替换数组中的第一个值,以及替换mValuesMap
  2. 保存属性名至全局变量mPropertyName
  3. 设置初始化标识false
    //用于保存属性名的数组
    PropertyValuesHolder[] mValues;
    //用于保存属性名的HashMap
    HashMap<String, PropertyValuesHolder> mValuesMap;

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

这样构造函数执行的内容都搞清楚了,继续看下面设置的代码

        animator.duration = 1000
        animator.startDelay = 300

这部分源码就很简单了,就是保存属性

// ObjectAnimator类中
   @Override
   @NonNull
   public ObjectAnimator setDuration(long duration) {
       super.setDuration(duration);
       return this;
   }

//父类ValueAnimator中
   @Override
   public ValueAnimator setDuration(long duration) {
       if (duration < 0) {
           throw new IllegalArgumentException("Animators cannot have negative duration: " +
                   duration);
       }
       mDuration = duration;
       return this;
   }

注册垂直同步信号

继续下一行代码animator.start()

这个方法里面主要操作一个是取消监听,一个是执行父类的start()方法。


    @Override
    public void start() {
        //AnimationHandler 并不是Android中的Handler,这里可以理解为一个单例工具类
        //取消掉animator之前设置的回调
        AnimationHandler.getInstance().autoCancelBasedOn(this);
        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();
    }

start()方法中首先后去获取了一个AnimationHandler对象的单例,再调用这个单例的autoCancelBasedOn()方法。
其实AnimationHandler对象并不是Android中的Handler,这里可以理解为一个工具类。
其中的autoCancelBasedOn()方法中执行的内容大致为遍历取消动画下一帧回调监听。(至于哪里注册、使用到这个监听,下面会讲到)


public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();

public static AnimationHandler getInstance() {
    if (sAnimatorHandler.get() == null) {
        sAnimatorHandler.set(new AnimationHandler());
    }
    return sAnimatorHandler.get();
}   

void autoCancelBasedOn(ObjectAnimator objectAnimator) {
       for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
           AnimationFrameCallback cb = mAnimationCallbacks.get(i);
           if (cb == null) {
               continue;
           }
           if (objectAnimator.shouldAutoCancel(cb)) {
               ((Animator) mAnimationCallbacks.get(i)).cancel();
           }
       }
   }

取消完监听之后调用了父类的start()方法,父类的start()方法中又调用了重载的start(false)方法。

这个重载的start(false)方法就比较重要了,一开始它检查了是否在UI线程执行,又设置动画是否反向播放(从来没有用过反向播放),反向播放的操作逻辑,以及一些状态设置等等。

接下来执行了它比较重要的三个方法addAnimationCallback(0)startAnimation();setCurrentPlayTime(0)

@Override
   public void start() {
       //重载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;
       // mSuppressSelfPulseRequested,这个值通过方法startWithoutPulsing设置,就把他默认当作false即可
       mSelfPulse = !mSuppressSelfPulseRequested;
       // 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;
       mAnimationEndRequested = 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 = -1;
       mFirstFrameTime = -1;
       mStartTime = -1;
       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) {
               // 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);
           }
       }
   }

addAnimationCallback(0)方法中,主要执行的逻辑就是前面提到过的AnimationHandler中注册AnimationFrameCallback监听。

因为前面移除了所有监听所以代码会执行getProvider().postFrameCallback(mFrameCallback)

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

  /**
     * AnimationHandler 的 addAnimationFrameCallback方法代码
     * Register to get a callback on the next frame after the delay.
     */
    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));
        }
    }

先看getProvider().postFrameCallback(mFrameCallback)这行代码的参数mFrameCallback,再去了解getProvider方法。

这是一个回调接口,回调方法doFrame中只要mAnimationCallbacks大于0就会调用getProvider().postFrameCallback(this),这就有点动画反复绘制的意思了。(doAnimationFrame方法下面再讲)

    private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                getProvider().postFrameCallback(this);
            }
        }
    };

继续看getProvider方法。方法中创建了一个对象MyFrameCallbackProvider

这个类又出现了一个比较重要的参数Choreographer

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

  //AnimationHandler 内部类
  private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {

      final Choreographer mChoreographer = Choreographer.getInstance();

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

可以看到前面回调函数中的重复调用的postFrameCallback方法中调用了Choreographer类中的postFrameCallback方法。

postFrameCallback方法中又调用了postFrameCallbackDelayed方法。

postFrameCallbackDelayed方法中又调用了postCallbackDelayedInternal方法。

  public void postFrameCallback(FrameCallback callback) {
      postFrameCallbackDelayed(callback, 0);
  }


  public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {
      if (callback == null) {
          throw new IllegalArgumentException("callback must not be null");
      }

      postCallbackDelayedInternal(CALLBACK_ANIMATION,
              callback, FRAME_CALLBACK_TOKEN, delayMillis);
  }

  private void postCallbackDelayedInternal(int callbackType,
                                           Object action, Object token, long delayMillis) {
      ......                
      synchronized (mLock) {
          final long now = SystemClock.uptimeMillis();
          final long dueTime = now + delayMillis;
          mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

          if (dueTime <= now) {
              scheduleFrameLocked(now);
          } else {
              Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
              msg.arg1 = callbackType;
              msg.setAsynchronous(true);
              mHandler.sendMessageAtTime(msg, dueTime);
          }
      }
  }

最终代码走到了scheduleFrameLocked(now)中,首先看到一个布尔值USE_VSYNC,这个值是用来表示是否开启垂直同步。


// Enable/disable vsync for animations and drawing.
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
    private static final boolean USE_VSYNC = SystemProperties.getBoolean(
            "debug.choreographer.vsync", true);

private void scheduleFrameLocked(long now) {
        if (!mFrameScheduled) {
            mFrameScheduled = true;
            if (USE_VSYNC) {
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "Scheduling next frame on vsync.");
                }

                // If running on the Looper thread, then schedule the vsync immediately,
                // otherwise post a message to schedule the vsync from the UI thread
                // as soon as possible.
                if (isRunningOnLooperThreadLocked()) {
                    scheduleVsyncLocked();
                } else {
                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                    msg.setAsynchronous(true);
                    mHandler.sendMessageAtFrontOfQueue(msg);
                }
            } else {
                final long nextFrameTime = Math.max(
                        mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
                if (DEBUG_FRAMES) {
                    Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                }
                Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextFrameTime);
            }
        }
    }

如果开启了垂直同步,则判断当前是否在Looper线程上运行,如果在Looper线程上运行,那么立即调度vsync,否则,从UI线程发布一条消息来调度vsync

FrameDisplayEventReceiver类中的scheduleVsync方法就是向native层注册监听垂直同步信号,其中参数mReceiverPtr就是一个jni层指向DisplayEventReceiver(的子类FrameDisplayEventReceiver)的指针,jni方法会回调FrameDisplayEventReceiveronVsync方法。

从UI线程发布一条消息来调度vsync最后也是执行了scheduleVsyncLocked方法。


    private void scheduleFrameLocked(long now) {
        .......
        if (isRunningOnLooperThreadLocked()) {
            scheduleVsyncLocked();
        } else {
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtFrontOfQueue(msg);
        }        
        ......
    }

    private final class FrameHandler extends Handler {
       @Override
       public void handleMessage(Message msg) {
           switch (msg.what) {
               .......
               case MSG_DO_SCHEDULE_VSYNC:
                   doScheduleVsync();
                   break;
               .......
           }
       }
   }

   void doScheduleVsync() {
        synchronized (mLock) {
            if (mFrameScheduled) {
                scheduleVsyncLocked();
            }
        }
    }

    private boolean isRunningOnLooperThreadLocked() {
        return Looper.myLooper() == mLooper;
    }

    private void scheduleVsyncLocked() {
        mDisplayEventReceiver.scheduleVsync();
    }

// FrameDisplayEventReceiver类中
    @UnsupportedAppUsage
    public void scheduleVsync() {
        if (mReceiverPtr == 0) {
            Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                    + "receiver has already been disposed.");
        } else {
            nativeScheduleVsync(mReceiverPtr);
        }
    }

收到垂直同步信号回调之后,onVsync方法被回调,这个方法的最后执行了发送HandleMessage.obtain(mHandler, this)),执行了自己的run方法。

private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable {

        @Override
        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
            ......
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }

        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
    }

run方法中调用了doFramedoFrame方法里面各种执行doCallbacks方法。

doCallbacks方法中先获取之前保存的callback,然后通过run方法执行callback,

    @UnsupportedAppUsage
    void doFrame(long frameTimeNanos, int frame) {
        ......
        try {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
            AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);

            mFrameInfo.markInputHandlingStart();
            doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

            mFrameInfo.markAnimationsStart();
            doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
            doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);

            mFrameInfo.markPerformTraversalsStart();
            doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

            doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
        } finally {
            AnimationUtils.unlockAnimationClock();
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        ......
    }


    void doCallbacks(int callbackType, long frameTimeNanos) {
       CallbackRecord callbacks;
       synchronized (mLock) {
            animation to start.
           final long now = System.nanoTime();
           //先获取之前保存的callback
           callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                   now / TimeUtils.NANOS_PER_MS);
           if (callbacks == null) {
               return;
           }
           mCallbacksRunning = true;

       ......

       try {
           Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
           for (CallbackRecord c = callbacks; c != null; c = c.next) {
             //执行callback
               c.run(frameTimeNanos);
           }
       } finally {
           synchronized (mLock) {
               mCallbacksRunning = false;
               do {
                   final CallbackRecord next = callbacks.next;
                   recycleCallbackLocked(callbacks);
                   callbacks = next;
               } while (callbacks != null);
           }
           Trace.traceEnd(Trace.TRACE_TAG_VIEW);
       }
   }

callback方法是从postCallbackDelayedInternal方法中加入队列的,所以上面的c就是回调方法。

private void postCallbackDelayedInternal(int callbackType,
           Object action, Object token, long delayMillis) {
       ......
           mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
       ......
   }

而这里的callback方法,就是Choreographer.FrameCallback,这就有回到了这里。

这个回调中先执行doAnimationFrame方法,再接续注册回调方法。

而在doAnimationFrame方法中比较重要的是这句callback.doAnimationFrame(frameTime),这里的callback就是ValueAnimator,这就回到了ValueAnimator中的doAnimationFrame方法。

private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
    @Override
    public void doFrame(long frameTimeNanos) {
        doAnimationFrame(getProvider().getFrameTime());
        if (mAnimationCallbacks.size() > 0) {
            getProvider().postFrameCallback(this);
        }
    }
};

private void doAnimationFrame(long frameTime) {
        long currentTime = SystemClock.uptimeMillis();
        final int size = mAnimationCallbacks.size();
        for (int i = 0; i < size; i++) {
            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
            if (callback == null) {
                continue;
            }
            if (isCallbackDue(callback, currentTime)) {
                callback.doAnimationFrame(frameTime);
                if (mCommitCallbacks.contains(callback)) {
                    getProvider().postCommitCallback(new Runnable() {
                        @Override
                        public void run() {
                            commitAnimationFrame(callback, getProvider().getFrameTime());
                        }
                    });
                }
            }
        }
        cleanUpList();
    }

//ValueAnimator 中
    getAnimationHandler().addAnimationFrameCallback(this, delay)

ValueAnimator中的doAnimationFrame方法。

一直深入进入,终于看到之前保存的mValues的使用,它被赋上了进度值,,这个方法中还回调了监听。

* @hide
   */
  public final boolean doAnimationFrame(long frameTime) {
      ......
      boolean finished = animateBasedOnTime(currentTime);

      if (finished) {
          endAnimation();
      }
      return finished;
  }

  boolean animateBasedOnTime(long currentTime) {
        boolean done = false;
        if (mRunning) {
            ......
            animateValue(currentIterationFraction);
        }
        return done;
    }

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

但是貌似还是少了和目标View关联。

ObjectAnimator类中的animateValue方法,有这样一句mValues[i].setAnimatedValue(target)关键语句

我们知道mValues中保存的是FloatPropertyValuesHolder对象,就是我们所保存的各个属性值


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

FloatPropertyValuesHolder类中setAnimatedValue中,mSetter不为空的时候利用反射执行了set方法。


   void setAnimatedValue(Object target) {
       if (mProperty != null) {
           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());
           }
       }
   }

初始化Setter方法

前面说到了三个重要的方法,现在说第二个startAnimation()

startAnimation()方法中执行了initAnimation()initAnimation()方法中调用了PropertyValuesHolder类的init()方法。

也没有什么特别的地方

   private void startAnimation() {
       if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
           Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                   System.identityHashCode(this));
       }

       mAnimationEndRequested = false;
       initAnimation();
       mRunning = true;
       if (mSeekFraction >= 0) {
           mOverallFraction = mSeekFraction;
       } else {
           mOverallFraction = 0f;
       }
       if (mListeners != null) {
           notifyStartListeners();
       }
   }

   @CallSuper
    void initAnimation() {
        if (!mInitialized) {
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].init();
            }
            mInitialized = true;
        }
    }

//  PropertyValuesHolder
    void init() {
       if (mEvaluator == null) {
           // We already handle int and float automatically, but not their Object
           // equivalents
           mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
                   (mValueType == Float.class) ? sFloatEvaluator :
                   null;
       }
       if (mEvaluator != null) {
           // KeyframeSet knows how to evaluate the common types - only give it a custom
           // evaluator if one has been set on this class
           mKeyframes.setEvaluator(mEvaluator);
       }
   }

再看ObjectAnimatorinitAnimation方法,会调用 FloatPropertyValuesHolder.setupSetterAndGetter(target)

这个方法中对之前没有找到的mSetter进行了赋值。

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

//  FloatPropertyValuesHolder 类中
  void setupSetterAndGetter(Object target) {
      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());
                  }
              }
          }
      }
  }

  void setupSetter(Class targetClass) {
       Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
       mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
   }

有了mSetter这个参数动画效果就能执行起来了。

往set方法总设置值

最后看看最后第一个关键方法setCurrentPlayTime(0)

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

 public void setCurrentFraction(float fraction) {
     initAnimation();
     fraction = clampFraction(fraction);
     mStartTimeCommitted = true; // do not allow start time to be compensated for jank
     if (isPulsingInternal()) {
         long seekTime = (long) (getScaledDuration() * fraction);
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         // Only modify the start time when the animation is running. Seek fraction will ensure
         // non-running animations skip to the correct start time.
         mStartTime = currentTime - seekTime;
     } else {
         // If the animation loop hasn't started, or during start delay, the startTime will be
         // adjusted once the delay has passed based on seek fraction.
         mSeekFraction = fraction;
     }
     mOverallFraction = fraction;
     final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
     animateValue(currentIterationFraction);
 }

会调用到animateValue(currentIterationFraction)方法,我们知道这个方法就是对view属性的更新,所以可以知道在调用了startAnimation()之后,就会立即进行一次view的更新操作,此时参数fraction为0。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值