| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
fange4828
8年前发布

Android Animator 源码分析

   <p>下面分析下Animator在Framework层的实现</p>    <h2>从ObjectAnimator.ofFloat()开始</h2>    <pre>  <code class="language-java">public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {      ObjectAnimator anim = new ObjectAnimator(target, propertyName);      anim.setFloatValues(values);      return anim;  }</code></pre>    <p>这个工厂方法会创建一个ObjectAnimator对象,在创建时同时设置属性动画的目标和属性名</p>    <pre>  <code class="language-java">private ObjectAnimator(Object target, String propertyName) {      setTarget(target);      setPropertyName(propertyName);  }</code></pre>    <pre>  <code class="language-java">// 设置目标对象  @Override  public void setTarget(@Nullable Object target) {      final Object oldTarget = getTarget();      if (oldTarget != target) {          if (isStarted()) {              cancel();          }          // target必须是一个弱引用对象          mTarget = target == null ? null : new WeakReference<Object>(target);          // New target should cause re-initialization prior to starting          mInitialized = false; // 记录尚未初始化,ValueAnimator的标志位,一会要用      }  }</code></pre>    <pre>  <code class="language-java">// 设置属性名称  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进行          // Animator只进行数值计算          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;  }</code></pre>    <p>ofFloat还有一步就是调用这个方法</p>    <pre>  <code class="language-java">@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          // 这是mProperty是为null的           if (mProperty != null) {              setValues(PropertyValuesHolder.ofFloat(mProperty, values));          } else {     setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));          }      } else {          super.setFloatValues(values);      }  }</code></pre>    <p>setValues这个过程有点长,按照顺序先写下吧</p>    <pre>  <code class="language-java">// PropertyValueHolder中  // 获取PropertyValuesHolder  public static PropertyValuesHolder ofFloat(String propertyName, float... values) {      // 创建子类      return new FloatPropertyValuesHolder(propertyName, values);  }      public FloatPropertyValuesHolder(String propertyName, float... values) {      super(propertyName);      setFloatValues(values);  }      @Override  public void setFloatValues(float... values) {      // 这个过程会取得value的类型      super.setFloatValues(values);      mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;  }    // super.setFloatValues()  // 取得Value的类型  public void setFloatValues(float... values) {      mValueType = float.class;      mKeyframes = KeyframeSet.ofFloat(values);  }</code></pre>    <p>然后设置KeyFrame了,KeyFrame时属性动画中的关键帧,通过设置关键帧来保证动画执行时序性</p>    <pre>  <code class="language-java">// ~KeyFrameSet中  public static KeyframeSet ofFloat(float... values) {      boolean badValue = false;      int numKeyframes = values.length;      FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];      // 如果获取只有一个数值,那么就只有开始和结束两个关键帧      if (numKeyframes == 1) {          // 实际创建关键帧          keyframes[0] = (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");      }      // 创建一个关键帧集合      return new FloatKeyframeSet(keyframes);  }</code></pre>    <p>接下来看关键帧怎么创建的</p>    <pre>  <code class="language-java">//keyFrame中  public static Keyframe ofFloat(float fraction) {      return new FloatKeyframe(fraction);  }    // FloatKeyFrame中  FloatKeyframe(float fraction) {      mFraction = fraction;      mValueType = float.class;  }</code></pre>    <p>仔细看了看,发现KeyFrame其实只是对当前的value和fraction进行一个记录,不同类型的KeyFrame会设置不同的mValueType</p>    <p>KeyFrame中的属性值,一会回来再看</p>    <pre>  <code class="language-java">/**   * Flag to indicate whether this keyframe has a valid value. This flag is used when an   * animation first starts, to populate placeholder keyframes with real values derived   * from the target object.   */  boolean mHasValue;    /**   * Flag to indicate whether the value in the keyframe was read from the target object or not.   * If so, its value will be recalculated if target changes.   */  boolean mValueWasSetOnStart;      /**   * The time at which mValue will hold true.   */  float mFraction;    /**   * The type of the value in this Keyframe. This type is determined at construction time,   * based on the type of the <code>value</code> object passed into the constructor.   */  Class mValueType;    /**   * The optional time interpolator for the interval preceding this keyframe. A null interpolator   * (the default) results in linear interpolation over the interval.   */  private TimeInterpolator mInterpolator = null;</code></pre>    <p>回来看哪个keyframe的ofFloat方法,最终会创建一个关键帧集合</p>    <pre>  <code class="language-java">public KeyframeSet(Keyframe... keyframes) {      mNumKeyframes = keyframes.length;      // immutable list      mKeyframes = Arrays.asList(keyframes);      mFirstKeyframe = keyframes[0];      mLastKeyframe = keyframes[mNumKeyframes - 1];      mInterpolator = mLastKeyframe.getInterpolator();  }</code></pre>    <p>ObjectAnimator的ofFloat过程就结束了,下面看下其他方法</p>    <h2>setDuration()</h2>    <p>设置动画的执行时间</p>    <p>这个就是将执行时间写入属性中,一会会用到</p>    <pre>  <code class="language-java">@Override  public ValueAnimator setDuration(long duration) {      if (duration < 0) {          throw new IllegalArgumentException("Animators cannot have negative duration: " +                  duration);      }      mDuration = duration;      return this;  }</code></pre>    <h2>setInterpolator()</h2>    <p>设置插值器,默认的插值器是带有加速度的</p>    <pre>  <code class="language-java">// The time interpolator to be used if none is set on the animation  private static final TimeInterpolator sDefaultInterpolator =          new AccelerateDecelerateInterpolator();</code></pre>    <pre>  <code class="language-java">@Override  public void setInterpolator(TimeInterpolator value) {      if (value != null) {          mInterpolator = value;      } else {          mInterpolator = new LinearInterpolator();      }  }</code></pre>    <h2>setEvaluator()</h2>    <p>设置估值器</p>    <p>估值器实际上是在KeyFrame中使用的</p>    <pre>  <code class="language-java">public void setEvaluator(TypeEvaluator value) {     if (value != null && mValues != null && mValues.length > 0) {         mValues[0].setEvaluator(value);     }  }</code></pre>    <pre>  <code class="language-java">public void setEvaluator(TypeEvaluator evaluator) {      mEvaluator = evaluator;      mKeyframes.setEvaluator(evaluator);  }</code></pre>    <pre>  <code class="language-java">//KeyFrameSet中  public void setEvaluator(TypeEvaluator evaluator) {      // 使用属性值进行保存      mEvaluator = evaluator;  }</code></pre>    <h2>start()</h2>    <p>开始分析开始动画的方法</p>    <p>从ObjectAnimator开始,会调用到ValueAnimator的start(boolean playBackwards)方法</p>    <pre>  <code class="language-java">// playBackwards 是否倒序播放,我们此时传入的是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.      // mSeekFraction这个标志位,第一次启动动画时是-1,暂时不会进入      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;      // 这里从线程中取出AnimatonHandler,一会分析      AnimationHandler animationHandler = AnimationHandler.getInstance();      animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));      // mStartedDelay指示这个动画是否已经从startDelay中开始执行。      // 这里mStartDelay=0可以顺利启动      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.              // 第一次启动,设置当前启动时间为0              setCurrentPlayTime(0);          } else {              setCurrentFraction(mSeekFraction);          }      }  }</code></pre>    <h3>AnimationHandler分析</h3>    <p>AnimationHandler 是一个实现了Runnable接口的ValueAnimator内部类</p>    <p>从当前线程中取得AnimationHandler对象</p>    <pre>  <code class="language-java">public static AnimationHandler getInstance() {      if (sAnimatorHandler.get() == null) {          sAnimatorHandler.set(new AnimationHandler());      }      return sAnimatorHandler.get();  }</code></pre>    <p>然后注册了两个回调,看下具体方法</p>    <pre>  <code class="language-java">/**   * 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));      }  }</code></pre>    <pre>  <code class="language-java">interface AnimationFrameCallback {    /**      * Run animation based on the frame time.      * @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time      *                  base.      */      // 每一帧动画开始时回调     void doAnimationFrame(long frameTime);       /**      * This notifies the callback of frame commit time. Frame commit time is the time after      * traversals happen, as opposed to the normal animation frame time that is before      * traversals. This is used to compensate expensive traversals that happen as the      * animation starts. When traversals take a long time to complete, the rendering of the      * initial frame will be delayed (by a long time). But since the startTime of the      * animation is set before the traversal, by the time of next frame, a lot of time would      * have passed since startTime was set, the animation will consequently skip a few frames      * to respect the new frameTime. By having the commit time, we can adjust the start time to      * when the first frame was drawn (after any expensive traversals) so that no frames      * will be skipped.      *      * @param frameTime The frame time after traversals happen, if any, in the      *                  {@link SystemClock#uptimeMillis()} time base.      */      // 每一帧开始遍历时回调     void commitAnimationFrame(long frameTime);  }</code></pre>    <p>从ValueAnimator中看下具体实现</p>    <pre>  <code class="language-java">// 这里对每一帧进行处理,如果时从暂停恢复,将调整开始时间  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);      }      // The frame time might be before the start time during the first frame of      // an animation.  The "current time" must always be on or after the start      // time to avoid animating frames at negative time intervals.  In practice, this      // is very rare and only happens when seeking backwards.      final long currentTime = Math.max(frameTime, mStartTime);      boolean finished = animateBasedOnTime(currentTime);        if (finished) {          endAnimation();      }  }</code></pre>    <p>这个回调也是遍历时调整启动时间的</p>    <pre>  <code class="language-java">public void commitAnimationFrame(long frameTime) {      if (!mStartTimeCommitted) {          mStartTimeCommitted = true;          long adjustment = frameTime - mLastFrameTime;          if (adjustment > 0) {              mStartTime += adjustment;              if (DEBUG) {                  Log.d(TAG, "Adjusted start time by " + adjustment + " ms: " + toString());              }          }      }  }</code></pre>    <h3>startAnimation()</h3>    <p>这段代码时start()中真正启动动画的代码, <strong>必须在UI线程</strong> ,仔细研究下</p>    <pre>  <code class="language-java">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();      }  }</code></pre>    <p>先会调用ObjectAnimator的initAnimation,只要是初始化反射的方法,对Target的属性值进行修改</p>    <pre>  <code class="language-java">@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();      }  }</code></pre>    <h2>PropertyValuesHolder的setupSetterAndGetter()</h2>    <p>初始化反射修改器,这里代码有点多</p>    <pre>  <code class="language-java">void setupSetterAndGetter(Object target) {      mKeyframes.invalidateCache();      if (mProperty != null) {          // check to make sure that mProperty is on the class of target          // try-catch判断是否这个属性在这个类里          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;          }      }      // 如果还没有找到属性的话,判断get和set方法是否存在      // 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) {              // 初始化setter              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) {                      // 初始化getter                      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());                  }              }          }      }  }</code></pre>    <p>继续寻找set和get方法</p>    <pre>  <code class="language-java">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);              }              // 放入map中              propertyMap.put(mPropertyName, setterOrGetter);          }      }      //返回给mSetter或mGetter      return setterOrGetter;  }</code></pre>    <h3>然后调用ValueAnimator的initAnimation</h3>    <p>这里会初始化每一个PropertyValuesHolder</p>    <pre>  <code class="language-java">void initAnimation() {      if (!mInitialized) {          int numValues = mValues.length;          for (int i = 0; i < numValues; ++i) {              // 这里会初始化每一个PropertyValuesHolder              mValues[i].init();          }          mInitialized = true;      }  }</code></pre>    <p>PropertyValuesHolder中的init()</p>    <pre>  <code class="language-java">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          // 给每一个KeyFrame设置估值器,前面讲过          mKeyframes.setEvaluator(mEvaluator);      }  }</code></pre>    <h3>start()中的setCurrentPlayTime()</h3>    <p>start()中调用的启动动画方法</p>    <pre>  <code class="language-java">public void setCurrentPlayTime(long playTime) {      // 计算fraction      float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;      setCurrentFraction(fraction);  }</code></pre>    <pre>  <code class="language-java">// 将计算出来的Fraction设置给动画  public void setCurrentFraction(float fraction) {      initAnimation();      fraction = clampFraction(fraction);      long seekTime = (long) (getScaledDuration() * fraction);      // 当前执行动画的时间      long currentTime = AnimationUtils.currentAnimationTimeMillis();      mStartTime = currentTime - seekTime;      mStartTimeCommitted = true; // do not allow start time to be compensated for jank      if (!isPulsingInternal()) {          // If the animation loop hasn't started, the startTime will be adjusted in the first          // frame based on seek fraction.          mSeekFraction = fraction;      }      mOverallFraction = fraction;      final float currentIterationFraction = getCurrentIterationFraction(fraction);      // 拿到Fraction以后,开始变化数值      animateValue(currentIterationFraction);  }</code></pre>    <h3>对动画数值进行运算</h3>    <p>先会调用ObjectAnimator中的animateValue</p>    <pre>  <code class="language-java">@Override  void animateValue(float fraction) {      final Object target = getTarget();      if (mTarget != null && target == null) {          // We lost the target reference, cancel and clean up.          cancel();          return;      }      // 这里调用ValueAnimator中的animateValue计算数值      // ValueAnimator与属性值无关的,一会再看      super.animateValue(fraction);      int numValues = mValues.length;      //反射修改每个方法值      //这里修改完这一轮动画就结束了      for (int i = 0; i < numValues; ++i) {          mValues[i].setAnimatedValue(target);      }  }</code></pre>    <p>ValueAnimator中的animateValue进行插值运算</p>    <pre>  <code class="language-java">void animateValue(float fraction) {      // 插值运算在这里      fraction = mInterpolator.getInterpolation(fraction);      // 获取当前的Fraction      mCurrentFraction = fraction;      int numValues = mValues.length;      for (int i = 0; i < numValues; ++i) {          // 对每个PropertyValuesHolder计算数值          mValues[i].calculateValue(fraction);      }      // 回调update监听器      if (mUpdateListeners != null) {          int numListeners = mUpdateListeners.size();          for (int i = 0; i < numListeners; ++i) {              mUpdateListeners.get(i).onAnimationUpdate(this);          }      }  }</code></pre>    <h3>PropertyValuesHolder中的calculateValue()</h3>    <p>通过获取的fraction,对每个属性值进行变化,这个过程通过反射进行</p>    <pre>  <code class="language-java">void calculateValue(float fraction) {     // 从KeyFrame中获取计算完成的属性值,我们来看下这个方法     Object value = mKeyframes.getValue(fraction);     // 这里取到属性值     mAnimatedValue = mConverter == null ? value : mConverter.convert(value);  }</code></pre>    <p>KeyFrameSet中的getValue()</p>    <pre>  <code class="language-java">//KeyFrameSet中  public Object getValue(float fraction) {      // Special-case optimization for the common case of only two keyframes      // 只有两个关键帧的情况      if (mNumKeyframes == 2) {          if (mInterpolator != null) {              fraction = mInterpolator.getInterpolation(fraction);          }          // 通过估值器进行取值          return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),                  mLastKeyframe.getValue());      }      // 此处处理多个关键帧的情况,取出俩个关键帧之前的Fraction      // 进行计算      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;      // 对两个关键帧之前的fraction使用估值器进行计算      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();  }</code></pre>    <h2>PropertyValueHolder中的setAnimatedValue()反射修改属性值</h2>    <p>如果是ofFloat创建的FloatPropertyValueHolder,那么该方法为</p>    <pre>  <code class="language-java">@Override  void setAnimatedValue(Object target) {      if (mFloatProperty != null) {          mFloatProperty.setValue(target, mFloatAnimatedValue);          return;      }      if (mProperty != null) {          mProperty.set(target, mFloatAnimatedValue);          return;      }      // 针对jni属性      if (mJniSetter != 0) {          nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);          return;      }      // 反射修改数值      if (mSetter != null) {          try {              mTmpValueArray[0] = mFloatAnimatedValue;              mSetter.invoke(target, mTmpValueArray);          } catch (InvocationTargetException e) {              Log.e("PropertyValuesHolder", e.toString());          } catch (IllegalAccessException e) {              Log.e("PropertyValuesHolder", e.toString());          }      }  }</code></pre>    <p>动画流程就是这样</p>    <p> </p>    <p>来自:http://blog.csdn.net/y874961524/article/details/53984282</p>    <p> </p>    
 本文由用户 fange4828 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
 转载本站原创文章,请注明出处,并保留原始链接、图片水印。
 本站是一个以用户分享为主的开源技术平台,欢迎各类分享!
 本文地址:https://www.open-open.com/lib/view/open1487921172480.html
源码分析 安卓开发 Android开发 移动开发