安卓属性动画源码解析

在看本文之前,可以先阅读以下官方文档关于Property Animation的一些介绍和用法,地址为http://developer.android.com/guide/topics/graphics/prop-animation.html

那么下面就来讲一下ValueAnimator和ObjectAnimator的工作原理。

 

1.ValueAnimator

ValueAnimator可以说是整个属性动画框架的核心类,动画的驱动就是在此类中实现的。下面举一个ValueAnimator的实例:

 

Java代码   收藏代码
  1. ValueAnimator anim= ValueAnimator.ofInt(040);  
  2. animation.setDuration(40);  
  3. animation.start();  

 

然后通过ValueAnimator的AnimatorUpdateListener可以得到动画执行每一帧所返回的值,

 

 

Java代码   收藏代码
  1. anim.addUpdateListener(new AnimatorUpdateListener() {  
  2.     @Override  
  3.         public void onAnimationUpdate(ValueAnimator animation) {  
  4.                 //frameValue是通过startValue和endValue以及Fraction计算出来的  
  5.         int frameValue = (Integer)animation.getAnimatedValue();  
  6.         //利用每一帧返回的值,可以做一些改变View大小,坐标,透明度等等操作  
  7.     }  
  8. });  

 

 

 究竟ValueAnimator是怎么工作的呢,让我根据以上代码一句一句的进行分析,首先来看ValueAnimator.ofInt(0, 40);

 

Java代码   收藏代码
  1. //ofInt或ofFloat提供的values最终都被包装成一个PropertyValuesHolder  
  2. //不同于ObjectAnimator这里提供的值必须两个以上,ObjectAnimator可以只提供一个endValue  
  3. public static ValueAnimator ofInt(int... values) {  
  4.     ValueAnimator anim = new ValueAnimator();  
  5.     anim.setIntValues(values);  
  6.     return anim;  
  7. }  
  8.   
  9. /** 
  10.  * 通过以下代码可以看出,PropertyValuesHolder以某种方式保存了values的值。 
  11.  * 在ValueAnimator中操作的都是valuesHolder对象 
  12.  * @param values 
  13.  */  
  14. public void setIntValues(int... values) {  
  15.     if (values == null || values.length == 0) {  
  16.         return;  
  17.     }  
  18.     if (mValues == null || mValues.length == 0) {  
  19.          //这里PropertyValuesHolder.ofInt提供的字符串参数为“”,是因为ValueAnimator并不提供目标对象,自然无法提供属性名称  
  20.         setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("", values)});  
  21.     } else {    //这里是为了处理重复设置  
  22.         PropertyValuesHolder valuesHolder = mValues[0];  
  23.         valuesHolder.setIntValues(values);  
  24.     }  
  25.     // New property/values/target should cause re-initialization prior to starting  
  26.     mInitialized = false;  
  27. }  
  28.   
  29. //把PropertyValuesHolder对象保存起来  
  30. public void setValues(PropertyValuesHolder... values) {  
  31.        int numValues = values.length;  
  32.        mValues = values;  
  33.        mInitialized = false;  
  34. }  
 

 

  下面再来看一下PropertyValuesHolder中是以什么方式来保存提供的values值的

Java代码   收藏代码
  1. /** 
  2.   *  IntPropertyValuesHolder继承自PropertyValuesHolder ,用来封装int类型的值 
  3. **/   
  4. public static PropertyValuesHolder ofInt(String propertyName, int... values) {  
  5.         return new IntPropertyValuesHolder(propertyName, values);  
  6.  }  

 

 来看IntPropertyValuesHolder类

 

Java代码   收藏代码
  1. public IntPropertyValuesHolder(String propertyName, int... values) {  
  2.     super(propertyName);  
  3.     setIntValues(values);  
  4. }  
  5.   
  6. /** 
  7.  * 这里会发现调用了父类的setIntValues方法, 
  8.  * 并且产生了一个mKeyframeSet对象 
  9.  * @param values 
  10.  */  
  11. @Override  
  12. public void setIntValues(int... values) {  
  13.     super.setIntValues(values);  
  14.     mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;  
  15. }  
 

 

 再回到PropertyValueHolder查看实现

 

Java代码   收藏代码
  1. /** 
  2.  * mValueType作用是确定ObjectAnimator执行set方法时 
  3.  * 的参数类型 
  4.  * 而values被包装成了一个KeyframeSet 
  5.  * @param values 
  6.  */  
  7. public void setIntValues(int... values) {  
  8.     mValueType = int.class;  
  9.     mKeyframeSet = KeyframeSet.ofInt(values);  
  10. }  
 

 

 再进入KeyframeSet查看KeyframeSet.ofInt(values)具体实现

 

Java代码   收藏代码
  1. /** 
  2.  * 从此方法可以看到,values数组中的每一个值都被包装成了IntKeyframe, 
  3.  * IntKeyframe保存一个当前值的fraction,value和mValueType。 
  4.  * IntKeyframeSet则保存是一组IntKeyframe的集合。 
  5.  * @param values 
  6.  * @return 
  7.  */  
  8. public static KeyframeSet ofInt(int... values) {  
  9.     int numKeyframes = values.length;  
  10.     IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];  
  11.     if (numKeyframes == 1) {    //这里只可能是ObjectAnimator才会发生,  
  12.         keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);   //这里value为0,默认从ObjectAnimator中的目标对象中得到  
  13.         keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);  
  14.     } else {  
  15.         keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);  
  16.         for (int i = 1; i < numKeyframes; ++i) {    //根据值个数拆分  
  17.             keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);  
  18.         }  
  19.     }  
  20.     return new IntKeyframeSet(keyframes);  
  21. }  
 

 

 从这里可以看到,当初始化ValueAnimator时,同时也把传入的每一个数据值包装成了一个Keyframe,

 并保存在KeyframeSet中,而KeyframeSet则是在PropertyValueHolder初始化的。

 

初始化工作完成了,然后通过animation.setDuration(40);设置duration的值,这个非常重要。

然后通过anim.start(),开始执行动画

 

Java代码   收藏代码
  1.    /** 
  2.   *所有执行了Start方法的ValueAnimator都会被临时保存在sAnimations 
  3.   */  
  4.  private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations =  
  5.          new ThreadLocal<ArrayList<ValueAnimator>>() {  
  6.              @Override  
  7.              protected ArrayList<ValueAnimator> initialValue() {  
  8.                  return new ArrayList<ValueAnimator>();  
  9.              }  
  10.          };  
  11.   
  12. /** 
  13.   *  
  14.   * @param playBackwards Whether the ValueAnimator should start playing in reverse. 
  15.   *  
  16.   */  
  17.  private void start(boolean playBackwards) {  
  18.     /** 
  19.      * 确保start方法是在UI线程中执行,因为UI线程在ActivityThread中 
  20.      * 会初始化一个Looper 
  21.      */  
  22.      if (Looper.myLooper() == null) {  
  23.          throw new AndroidRuntimeException("Animators may only be run on Looper threads");  
  24.      }  
  25.      mPlayingBackwards = playBackwards;  
  26.      mCurrentIteration = 0;  
  27.      mPlayingState = STOPPED;   //动画初始执行状态  
  28.      mStarted = true;  
  29.      mStartedDelay = false;  
  30.      sPendingAnimations.get().add(this);      //所有执行start方法的ValueAnimator都会被临时保存到此集合  
  31.      if (mStartDelay == 0) {          
  32.          // This sets the initial value of the animation, prior to actually starting it running  
  33.          setCurrentPlayTime(getCurrentPlayTime());  
  34.          mPlayingState = STOPPED;  
  35.          mRunning = true;  
  36.   
  37.          if (mListeners != null) {        
  38.              ArrayList<AnimatorListener> tmpListeners =  
  39.                      (ArrayList<AnimatorListener>) mListeners.clone();  
  40.              int numListeners = tmpListeners.size();  
  41.              for (int i = 0; i < numListeners; ++i) {  
  42.                 //告诉注册的了这个动画的所有监听,动画已经开始运行  
  43.                  tmpListeners.get(i).onAnimationStart(this);    
  44.              }  
  45.          }  
  46.      }  
  47.      AnimationHandler animationHandler = sAnimationHandler.get();  
  48.      if (animationHandler == null) {      
  49.         //初始化唯一一个animationHandler  
  50.          animationHandler = new AnimationHandler();  
  51.          sAnimationHandler.set(animationHandler);  
  52.      }  
  53.        
  54.      animationHandler.sendEmptyMessage(ANIMATION_START);  
  55.  }  
  56.   
  57.  @Override  
  58.  public void start() {  
  59.      start(false);  
  60.  }  
 

 

  属性动画逐帧更新都是由handler不断发生消息来实现的,下面就来看一下 AnimationHandler的实现

 

Java代码   收藏代码
  1.    /** 
  2.   * 马上就开始执行的动画集合 
  3.   */  
  4.  private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations =  
  5.          new ThreadLocal<ArrayList<ValueAnimator>>() {  
  6.              @Override  
  7.              protected ArrayList<ValueAnimator> initialValue() {  
  8.                  return new ArrayList<ValueAnimator>();  
  9.              }  
  10.          };  
  11.   /** 
  12.   * 需要延时执行的所有动画都会被临时保存到sDelayedAnims 
  13.   */  
  14.  private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims =  
  15.          new ThreadLocal<ArrayList<ValueAnimator>>() {  
  16.              @Override  
  17.              protected ArrayList<ValueAnimator> initialValue() {  
  18.                  return new ArrayList<ValueAnimator>();  
  19.              }  
  20.          };  
  21.    
  22.  /** 
  23.   * 执行结束的所有动画都会被临时保存到sEndingAnims 
  24.   */  
  25.  private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims =  
  26.          new ThreadLocal<ArrayList<ValueAnimator>>() {  
  27.              @Override  
  28.              protected ArrayList<ValueAnimator> initialValue() {  
  29.                  return new ArrayList<ValueAnimator>();  
  30.              }  
  31.          };  
  32.              
  33.          
  34.   
  35.   
  36. /** 
  37.   *  
  38.   * 用来驱动动画执行的handler, 
  39.   * 所有的属性动画都会用同一个handler来处理。 
  40.   * 此handler主要处理动画开始动作,以及动画的每一帧 
  41.   */  
  42.  private static class AnimationHandler extends Handler {  
  43.      @Override  
  44.      public void handleMessage(Message msg) {  
  45.          boolean callAgain = true;  
  46.          //已经准备开始执行的动画  
  47.          ArrayList<ValueAnimator> animations = sAnimations.get();  
  48.          //需要延迟执行的动画  
  49.          ArrayList<ValueAnimator> delayedAnims = sDelayedAnims.get();  
  50.          switch (msg.what) {  
  51.              //start方法执行后,会发送消息执行ANIMATION_START中的代码  
  52.              case ANIMATION_START:  
  53.                  ArrayList<ValueAnimator> pendingAnimations = sPendingAnimations.get();  
  54.                  if (animations.size() > 0 || delayedAnims.size() > 0) {  
  55.                      callAgain = false;  
  56.                  }  
  57.                    
  58.                  /** 
  59.                   * 由于一个动画的开始可能触发另外一个动画,意味着可能有新的动画被添加进pendingAnimations, 
  60.                   * 所以这里不断遍历直到pendingAnimations为空 
  61.                   */  
  62.                  while (pendingAnimations.size() > 0) {  
  63.                      ArrayList<ValueAnimator> pendingCopy =  
  64.                              (ArrayList<ValueAnimator>) pendingAnimations.clone();  
  65.                      pendingAnimations.clear();  
  66.                      int count = pendingCopy.size();  
  67.                      for (int i = 0; i < count; ++i) {  
  68.                          ValueAnimator anim = pendingCopy.get(i);  
  69.                          //如果动画没有延迟时间,则把动画添加进入sAnimations,意味着动画即将执行  
  70.                          if (anim.mStartDelay == 0) {  
  71.                              anim.startAnimation();  
  72.                          } else { //如果动画有一个延迟执行时间,则把动画添加进延迟集合delayedAnims  
  73.                              delayedAnims.add(anim);  
  74.                          }  
  75.                      }  
  76.                  }  
  77.               // 注意,这里没有break,那么ANIMATION_FRAME中代码将继续执行  
  78.              case ANIMATION_FRAME:  
  79.                  //获取当前时间,通过减去startTime,计算差值  
  80.                  long currentTime = AnimationUtils.currentAnimationTimeMillis();  
  81.                  ArrayList<ValueAnimator> readyAnims = sReadyAnims.get();  
  82.                  ArrayList<ValueAnimator> endingAnims = sEndingAnims.get();  
  83.   
  84.                  //这里检查delayedAnims中动画是否可以被执行,我们可以不管这部分  
  85.                  int numDelayedAnims = delayedAnims.size();  
  86.                  for (int i = 0; i < numDelayedAnims; ++i) {  
  87.                      ValueAnimator anim = delayedAnims.get(i);  
  88.                      if (anim.delayedAnimationFrame(currentTime)) {  
  89.                          readyAnims.add(anim);  
  90.                      }  
  91.                  }  
  92.                  int numReadyAnims = readyAnims.size();  
  93.                  if (numReadyAnims > 0) {  
  94.                      for (int i = 0; i < numReadyAnims; ++i) {  
  95.                          ValueAnimator anim = readyAnims.get(i);  
  96.                          anim.startAnimation();  
  97.                          anim.mRunning = true;  
  98.                          delayedAnims.remove(anim);  
  99.                      }  
  100.                      readyAnims.clear();  
  101.                  }  
  102.   
  103.                  //接着看这里。  
  104.                  int numAnims = animations.size();  
  105.                  int i = 0;  
  106.                  while (i < numAnims) {  
  107.                      ValueAnimator anim = animations.get(i);  
  108.                      //animationFrame方法返回true,意味着此动画已经执行完毕,  
  109.                      //否则开始真正计算AnimatedValue的值,大家可以根据  
  110.                      //getAnimationValue来获取这个值,在ObjectAnimator中  
  111.                      //此方法还会不断设置object中的属性值  
  112.                      if (anim.animationFrame(currentTime)) {  
  113.                          endingAnims.add(anim);  
  114.                      }  
  115.                      if (animations.size() == numAnims) {  
  116.                          ++i;  
  117.                      } else {   //这里是处理当前正在执行的动画,被cancle的情况  
  118.                          // An animation might be canceled or ended by client code  
  119.                          // during the animation frame. Check to see if this happened by  
  120.                          // seeing whether the current index is the same as it was before  
  121.                          // calling animationFrame(). Another approach would be to copy  
  122.                          // animations to a temporary list and process that list instead,  
  123.                          // but that entails garbage and processing overhead that would  
  124.                          // be nice to avoid.  
  125.                          --numAnims;  
  126.                          endingAnims.remove(anim);  
  127.                      }  
  128.                  }  
  129.                  //处理执行结束后的动画,结束后会把动画从所有集合中移除,  
  130.                  //并且触发监听通知用户  
  131.                  if (endingAnims.size() > 0) {  
  132.                      for (i = 0; i < endingAnims.size(); ++i) {  
  133.                          endingAnims.get(i).endAnimation();  
  134.                      }  
  135.                      endingAnims.clear();  
  136.                  }  
  137.   
  138.                   
  139.                  //如果任然有活动的动画或者延迟执行的动画,会继续执行下一帧  
  140.                  //执行下一帧的时间在0-10ms之间  
  141.                  if (callAgain && (!animations.isEmpty() || !delayedAnims.isEmpty())) {  
  142.                      sendEmptyMessageDelayed(ANIMATION_FRAME, Math.max(0, sFrameDelay -  
  143.                          (AnimationUtils.currentAnimationTimeMillis() - currentTime)));  
  144.                  }  
  145.                  break;  
  146.          }  
  147.      }  
  148.  }  
 

 

  在handler逐帧更新代码中,anim.animationFrame(currentTime),是计算动画执行过程中,值的变化的,

  

Java代码   收藏代码
  1. boolean animationFrame(long currentTime) {  
  2.        boolean done = false;  
  3.   
  4.        switch (mPlayingState) {  
  5.        case RUNNING:  
  6.        case SEEKED:  
  7.         //这句代码是重点,通过currentTime和mStartTime的差值计算动画执行的进度,0-1的小数值  
  8.            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;  
  9.            if (fraction >= 1f) { //这里是处理动画是否执行完毕的逻辑,暂时可以不用看  
  10.                if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {  
  11.                    // Time to repeat  
  12.                    if (mListeners != null) {  
  13.                        int numListeners = mListeners.size();  
  14.                        for (int i = 0; i < numListeners; ++i) {  
  15.                            mListeners.get(i).onAnimationRepeat(this);  
  16.                        }  
  17.                    }  
  18.                    if (mRepeatMode == REVERSE) {  
  19.                        mPlayingBackwards = mPlayingBackwards ? false : true;  
  20.                    }  
  21.                    mCurrentIteration += (int)fraction;  
  22.                    fraction = fraction % 1f;  
  23.                    mStartTime += mDuration;  
  24.                } else {  
  25.                    done = true;  
  26.                    fraction = Math.min(fraction, 1.0f);  
  27.                }  
  28.            }  
  29.            //真正计算animationValue和执行onAnimationUpdate回调的  
  30.            //方法在这里  
  31.            animateValue(fraction);  
  32.            break;  
  33.        }  
  34.   
  35.        return done;  
  36.    }  

 

   animationValue方法通过插值器重新计算一个fraction,

   

Java代码   收藏代码
  1. /** 
  2.     *  
  3.     * 
  4.     * @param fraction 通过总时间和已经执行时间,计算出来的动画进度 
  5.     */  
  6.    void animateValue(float fraction) {  
  7.     //通过插值器,对fraction重新计算,插值器不同计算出来的结果不同,  
  8.     //这个跟Tween动画时一样的  
  9.        fraction = mInterpolator.getInterpolation(fraction);  
  10.        mCurrentFraction = fraction;  
  11.        int numValues = mValues.length;  
  12.        for (int i = 0; i < numValues; ++i) {  
  13.            mValues[i].calculateValue(fraction); //真正计算animationValue的方法  
  14.        }  
  15.        //没一帧的执行都会执行回调,这样使用者就能获取每一帧计算出来的animationValue了  
  16.        if (mUpdateListeners != null) {  
  17.            int numListeners = mUpdateListeners.size();  
  18.            for (int i = 0; i < numListeners; ++i) {  
  19.                mUpdateListeners.get(i).onAnimationUpdate(this);  
  20.            }  
  21.        }  
  22.    }  

 

 

 真正的计算是交给PropertyValuesHolder.calculateValue(float fraction)计算,之前我们看到传进来的values值已经被PropertyValuesHolder包装并保存起来了,那么现在我们就可以利用到这些值来进行计算了。

 

Java代码   收藏代码
  1. void calculateValue(float fraction) {  
  2.      mAnimatedValue = mKeyframeSet.getValue(fraction);  
  3.  }  

 

查看IntKeyframeSet

  

Java代码   收藏代码
  1. public int getIntValue(float fraction) {  
  2.     if (mNumKeyframes == 2) {    //当只有firstValue和lastValue时,发现最终是通过mEvaluator.evaluate来计算mAnimatedValue  
  3.         if (firstTime) {  
  4.             firstTime = false;  
  5.             firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();  
  6.             lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();  
  7.             deltaValue = lastValue - firstValue;  
  8.         }  
  9.         if (mInterpolator != null) {  
  10.             fraction = mInterpolator.getInterpolation(fraction);  
  11.         }  
  12.         //真正计算出mAnimatedValue的地方  
  13.         if (mEvaluator == null) {  
  14.             return firstValue + (int)(fraction * deltaValue);  
  15.         } else {  
  16.             return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();  
  17.         }  
  18.     }  
  19.   
  20. //后面这些复制的操作可以先不看,是处理类似OvershootInterpolator插值器(超过给定值,再回来),和AnticipateInterpolator,先小于给定初始值,再正常继续执行,以及BounceInterpolator,弹性动作  
  21.     if (fraction <= 0f) {  
  22.         final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);  
  23.         final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1);  
  24.         int prevValue = prevKeyframe.getIntValue();  
  25.         int nextValue = nextKeyframe.getIntValue();  
  26.         float prevFraction = prevKeyframe.getFraction();  
  27.         float nextFraction = nextKeyframe.getFraction();  
  28.         final TimeInterpolator interpolator = nextKeyframe.getInterpolator();  
  29.         if (interpolator != null) {  
  30.             fraction = interpolator.getInterpolation(fraction);  
  31.         }  
  32.         float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);  
  33.         return mEvaluator == null ?  
  34.                 prevValue + (int)(intervalFraction * (nextValue - prevValue)) :  
  35.                 ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).  
  36.                         intValue();  
  37.     } else if (fraction >= 1f) {  
  38.         final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2);  
  39.         final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1);  
  40.         int prevValue = prevKeyframe.getIntValue();  
  41.         int nextValue = nextKeyframe.getIntValue();  
  42.         float prevFraction = prevKeyframe.getFraction();  
  43.         float nextFraction = nextKeyframe.getFraction();  
  44.         final TimeInterpolator interpolator = nextKeyframe.getInterpolator();  
  45.         if (interpolator != null) {  
  46.             fraction = interpolator.getInterpolation(fraction);  
  47.         }  
  48.         float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);  
  49.         return mEvaluator == null ?  
  50.                 prevValue + (int)(intervalFraction * (nextValue - prevValue)) :  
  51.                 ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();  
  52.     }  
  53.     IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);  
  54.     for (int i = 1; i < mNumKeyframes; ++i) {  
  55.         IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);  
  56.         if (fraction < nextKeyframe.getFraction()) {  
  57.             final TimeInterpolator interpolator = nextKeyframe.getInterpolator();  
  58.             if (interpolator != null) {  
  59.                 fraction = interpolator.getInterpolation(fraction);  
  60.             }  
  61.             float intervalFraction = (fraction - prevKeyframe.getFraction()) /  
  62.                 (nextKeyframe.getFraction() - prevKeyframe.getFraction());  
  63.             int prevValue = prevKeyframe.getIntValue();  
  64.             int nextValue = nextKeyframe.getIntValue();  
  65.             return mEvaluator == null ?  
  66.                     prevValue + (int)(intervalFraction * (nextValue - prevValue)) :  
  67.                     ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).  
  68.                             intValue();  
  69.         }  
  70.         prevKeyframe = nextKeyframe;  
  71.     }  
  72.     // shouldn't get here  
  73.     return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();  
  74. }  

 

看类IntEvaluator

 

Java代码   收藏代码
  1. /** 
  2.  * 这里其实比较简单,通过startValue,endValue和fraction(动画执行的进度),计算出动画执行  *的中间值 
  3. **/   
  4. public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
  5.         int startInt = startValue;  
  6.         return (int)(startInt + fraction * (endValue - startInt));  
  7.     }  

 

 这样每一帧都会计算出当前进度的animationValue,而我们根据AnimatorUpdateListener就可以获取每一帧计算过后animationValue值了。

这样关于ValueAnimator工作的基本过程就都讲清楚了。下面看看ObjectAnimator。

 

2.ObjectAnimator

 ObjectAnimator是通过传递进来一个对象,以及对象的属性名称,在anim.start()执行过程中不断更改对象的属性值,来实现动画效果的。

前提是传递进来的对象的属性,必须要具有相应的set和get方法。

 ObjectAnimator是继承自ValueAnimator,前者的许多方法其实是调用ValueAnimator的方法,所以说ValueAnimator是动画核心,因为它处理了

驱动引擎这一块。ObjectAnimator多传入了两个参数,一个是target对象(可以是任何对象,不限于View),一个是对象属性propertyName(前提是所属对象必须拥有对应的setPropertyName(),getPropertyName方法)

下面还是来看一个ObjectAnimator的简单的例子:

 

Java代码   收藏代码
  1. ObjectAnimator anm = ObjectAnimator.ofFloat(myView, "alpha"1);  
  2. anm.setDuration(200);  
  3. anm.start();  
 

 

 代码的作用是对View的alpha值进行更改,注意这里可以只提供一个value值,而ValueAnimator则必须提供两个值以上。这是因为:这里提供的一个值是作为

endValue,startValue则是通过myView.getAlpha()来获得。下面再来看看ObjectAnimator.ofFloat()方法:

 

Java代码   收藏代码
  1. public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {  
  2.        ObjectAnimator anim = new ObjectAnimator(target, propertyName);  
  3.        anim.setFloatValues(values);  
  4.        return anim;  
  5.    }  
 

 

 注意看,这里实例化ObjectAnimator多传入了target对象和其对于的属性名称propertyName,这里的作用是在动画改变的过程中,不断通过对象的setPropertyName方法改变PropertyName的值,

在样在不断的重绘过程中获得新的值,就能实现动画效果了。当然View提供的set方法可能稍微更复杂一些,不过意思还是一样的。

下面继续看代码:

 

Java代码   收藏代码
  1. private ObjectAnimator(Object target, String propertyName) {  
  2.     mTarget = target;  
  3.     setPropertyName(propertyName);    
  4. }  
   

 

   再看setFloatValues方法

 

Java代码   收藏代码
  1. public void setFloatValues(float... values) {  
  2.        //第一次初始化时,mValues肯定为null,这里初始化它  
  3.        if (mValues == null || mValues.length == 0) {  
  4.            // No values yet - this animator is being constructed piecemeal. Init the values with  
  5.            // whatever the current propertyName is  
  6.            if (mProperty != null) {  
  7.                setValues(PropertyValuesHolder.ofFloat(mProperty, values));  
  8.            } else {     
  9.                //之前我们说过提供的值都被保存到PropertyValuesHolder  
  10.                //这里还提供了propertyName,标志改变的是哪个属性的值  
  11.                //在初始化set,get方法实例时会被调用  
  12.                setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));  
  13.            }  
  14.        } else {  
  15.            super.setFloatValues(values);  
  16.        }  
  17.    }  
 

 

后续的setDuration,start动画,都和ValueAnimator一样,执行的流程都是相同的,不同的是ObjectAnimator重写了几个方法,让其执行了更多的操作,我们依次来看看重写了哪几个方法,

首先是重写了initAnimation(),此方法会在动画执行之前调用。

 

Java代码   收藏代码
  1. @Override  
  2.    void initAnimation() {  
  3.        if (!mInitialized) {  
  4.            //果然在PropertyValuesHolder中实例化了mTarget对象的对应  
  5.         //属性的set,get方法,propertyName已经在实例化PropertyValuesHolder  
  6.         //的时候传递给了它。  
  7.            int numValues = mValues.length;  
  8.            for (int i = 0; i < numValues; ++i) {  
  9.                mValues[i].setupSetterAndGetter(mTarget);  
  10.            }  
  11.            super.initAnimation();  
  12.        }  
  13.    }  
 

 

现在具体看下setUpSetterAndGetter的实现细节

 

Java代码   收藏代码
  1. void setupSetterAndGetter(Object target) {  
  2.         Class targetClass = target.getClass();  
  3.         if (mSetter == null) {  
  4.             setupSetter(targetClass);      //初始化setter方法  
  5.         }  
  6.         //之前在ValueAnimator中说过,一个keyFrame对应于一个传进来的  
  7.         //value值,如果values值没有设置,会在这里调用get方法设置startValue  
  8.         for (Keyframe kf : mKeyframeSet.mKeyframes) {  
  9.             if (!kf.hasValue()) {  
  10.                 if (mGetter == null) {     //初始化getter方法  
  11.                     setupGetter(targetClass);  
  12.                 }  
  13.                 try {  
  14.                     //通过get方法设置startValue  
  15.                     kf.setValue(mGetter.invoke(target));  
  16.                 } catch (InvocationTargetException e) {  
  17.                     Log.e("PropertyValuesHolder", e.toString());  
  18.                 } catch (IllegalAccessException e) {  
  19.                     Log.e("PropertyValuesHolder", e.toString());  
  20.                 }  
  21.             }  
  22.         }  
  23.     }  
 

 

下面是set,get方法具体实现

 

Java代码   收藏代码
  1. void setupSetter(Class targetClass) {  
  2.        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);  
  3.    }  
  4.    private void setupGetter(Class targetClass) {  
  5.        mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get"null);  
  6.    }  
  7.      
  8.    /** 
  9.     *  
  10.     * @param targetClass  传入的target对应的class对象 
  11.     * @param propertyMapMap  这是静态集合,缓存所有ObjectAnimator中target对应的set,get方法 
  12.     * @param prefix  set或get前缀 
  13.     * @param valueType set方法对应的参数类型 
  14.     * @return 
  15.     */  
  16.    private Method setupSetterOrGetter(Class targetClass,  
  17.            HashMap<Class, HashMap<String, Method>> propertyMapMap,  
  18.            String prefix, Class valueType) {  
  19.        Method setterOrGetter = null;  
  20.        try {  
  21.            // Have to lock property map prior to reading it, to guard against  
  22.            // another thread putting something in there after we've checked it  
  23.            // but before we've added an entry to it  
  24.            mPropertyMapLock.writeLock().lock();  
  25.            //先从缓存查看  
  26.            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);  
  27.            if (propertyMap != null) {  
  28.                setterOrGetter = propertyMap.get(mPropertyName);  
  29.            }  
  30.            if (setterOrGetter == null) {  
  31.             //真正用反射获取set,get方法Method实例的地方  
  32.                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);  
  33.                if (propertyMap == null) {  
  34.                    propertyMap = new HashMap<String, Method>();  
  35.                    propertyMapMap.put(targetClass, propertyMap);  
  36.                }  
  37.                //缓存到集合  
  38.                propertyMap.put(mPropertyName, setterOrGetter);  
  39.            }  
  40.        } finally {  
  41.            mPropertyMapLock.writeLock().unlock();  
  42.        }  
  43.        return setterOrGetter;  
  44.    }  
  45.      
  46.    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {  
  47.        // TODO: faster implementation...  
  48.        Method returnVal = null;  
  49.        //根据前缀set或get,和传入的mPropertyName组合成方法名  
  50.        //比如alpha会组合成setAlpha和getAlpha  
  51.        String methodName = getMethodName(prefix, mPropertyName);  
  52.        Class args[] = null;  
  53.        if (valueType == null) {   //无参数,这是get方法  
  54.            try {  
  55.                returnVal = targetClass.getMethod(methodName, args);  
  56.            } catch (NoSuchMethodException e) {  
  57.                Log.e("PropertyValuesHolder",  
  58.                        "Couldn't find no-arg method for property " + mPropertyName + ": " + e);  
  59.            }  
  60.        } else {        
  61.         //获得set方法Method对象,这里稍微复杂一点,其实也很简单,就是重试了多次,选定多个参数  
  62.         //type类型,防止一出错就放弃了,  
  63.            args = new Class[1];  
  64.            Class typeVariants[];  
  65.            if (mValueType.equals(Float.class)) {  
  66.                typeVariants = FLOAT_VARIANTS;  
  67.            } else if (mValueType.equals(Integer.class)) {  
  68.                typeVariants = INTEGER_VARIANTS;  
  69.            } else if (mValueType.equals(Double.class)) {  
  70.                typeVariants = DOUBLE_VARIANTS;  
  71.            } else {  
  72.                typeVariants = new Class[1];  
  73.                typeVariants[0] = mValueType;  
  74.            }  
  75.            for (Class typeVariant : typeVariants) {  
  76.                args[0] = typeVariant;  
  77.                try {  
  78.                    returnVal = targetClass.getMethod(methodName, args);  
  79.                    // change the value type to suit  
  80.                    mValueType = typeVariant;  
  81.                    return returnVal;  
  82.                } catch (NoSuchMethodException e) {  
  83.                    // Swallow the error and keep trying other variants  
  84.                }  
  85.            }  
  86.          
  87.        }  
  88.        return returnVal;  
  89.    }  
 

 

   至此,set和get方法的初始化和缓存就全部结束了。

 

再看ValueAnimator重写的另一个方法animateValue

 

Java代码   收藏代码
  1. /** 
  2.      * 在ValueAnimator中知道,animateValue是在动画执行过程中, 
  3.      * 在animationFrame中执行的,这里除了执行父类的animateValue, 
  4.      * 计算每一帧得到的animationValue值,还把这个值通过setAnimatedValue 
  5.      * 设置到了目标对象的属性中 
  6.      * @param fraction 
  7.      */  
  8.     @Override  
  9.     void animateValue(float fraction) {  
  10.         super.animateValue(fraction);  
  11.         int numValues = mValues.length;  
  12.         for (int i = 0; i < numValues; ++i) {  
  13.             //通过此方法,把父类计算出的animationValue  
  14.             //通过set方法设置目标对象传入的属性中  
  15.             mValues[i].setAnimatedValue(mTarget);  
  16.         }  
  17.     }  
 

 

 看看其具体实现

 

Java代码   收藏代码
  1. void setAnimatedValue(Object target) {  
  2.       if (mSetter != null) {  
  3.           try {  
  4.               mTmpValueArray[0] = getAnimatedValue();  
  5.               //反射执行set方法,传入每一帧计算得到的AnimatedValue值  
  6.               mSetter.invoke(target, mTmpValueArray);  
  7.           } catch (InvocationTargetException e) {  
  8.               Log.e("PropertyValuesHolder", e.toString());  
  9.           } catch (IllegalAccessException e) {  
  10.               Log.e("PropertyValuesHolder", e.toString());  
  11.           }  
  12.       }  
  13.   }  
 

 

到这里具体的实现就基本完成了,我们看到ObjectAnimator与ValueAnimator只有3个地方不同,

其一是提供了Object对象,以及对象的propertyName

其二是重写initAnimation方法,额外初始化了对应属性的set和get方法

其三就是重写animateValue,把每一帧计算的到的中间值通过set方法传入对象属性中。

 

ObjectAnimator实现基本就是这些东西。

 

3.更多

 

如果ValueAnimator要传入多个属性值有这几种方法

Java代码   收藏代码
  1. 1.Multiple ObjectAnimator objects  
  2.   
  3. ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);  
  4. ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);  
  5. AnimatorSet animSetXY = new AnimatorSet();  
  6. animSetXY.playTogether(animX, animY);  
  7. animSetXY.start();  
  8.   
  9. 2.One ObjectAnimator  
  10.   
  11. PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);  
  12. PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);  
  13. ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();  
  14. ViewPropertyAnimator  
  15.   
  16. 3//这是view独有的  
  17. myView.animate().x(50f).y(100f);  

 

 如果要多次改变动画效果,可以直接设置keyFrame,

Java代码   收藏代码
  1. //前半段从0变到360度,后半段从360度变回0度  
  2. Keyframe kf0 = Keyframe.ofFloat(0f, 0f);  
  3. Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);  
  4. Keyframe kf2 = Keyframe.ofFloat(1f, 0f);  
  5. PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);  
  6. ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)  
  7. rotationAnim.setDuration(5000ms);  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android属性动画是一种用于在Android应用程序中创建动画效果的框架。它允许您对任意对象的属性进行动画处理,而不仅仅是视图对象。使用属性动画,您可以平滑地改变对象的属性,如位置、大小、颜色等,从而创建流畅的动画效果。 属性动画的基本概念是通过改变对象的属性值来实现动画效果,而不是通过改变视图的位置或绘制来实现。这使得属性动画比传统的补间动画更加灵活和强大。 要使用属性动画,您需要创建一个Animator对象,并指定要动画化的目标对象和属性。然后,您可以定义动画的持续时间、插值器和监听器等属性。最后,启动动画并观察目标对象的属性值的平滑变化。 以下是一个简单的示例,演示如何使用属性动画来平滑地改变视图对象的透明度: ```java // 创建一个属性动画对象,指定要改变的属性为视图对象的透明度 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha",***.setDuration(1000); // 设置插值器,控制动画的变化速率 animator.setInterpolator(new AccelerateDecelerateInterpolator()); // 启动动画 animator.start(); ``` 在上面的示例中,我们创建了一个ObjectAnimator对象,指定要改变的属性为视图对象的透明度。然后,我们设置了动*** 除了ObjectAnimator,Android还提供了一些其他类型的属性动画,如ValueAnimator和AnimatorSet。这些类可用于更复杂的动画效果,如同时播放多个动画或在动画中修改多个属性。 希望这个简介能帮助您理解Android属性动画的基本概念和用法。如果您有更多问题,请随时提问!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值