Android - Animation(一)一文总结了android中的补间动画ViewAnimation/Tween Animation)和帧动画DrawableAnimation/Frame Animation)的使用

本篇文章主要解析属性动画(Property Animation,android3.0引入)的实现原理


下篇 属性动画的实现原理


先来看属性动画的最简单实现:

第一种方式:先在/res/animator/目录下创建translate.xml文件定义动画,再在Java文件中引用并开启
// 首先在/res/animator/目录下创建translate.xml文件,内容如下:<?xml version="1.0" encoding="utf-8"?>  <objectAnimator       xmlns:android="http://schemas.android.com/apk/res/android"       android:propertyName="translationX"  //设置动画需要改变的属性名称    android:duration="2000"  //设置动画的持续时间    android:valueFrom="0.0"  //设置动画的初始值(对应上边设置的属性)    android:valueTo="20.0">  //设置动画的结束值(对应上边设置的属性)</objectAnimator>//然后在Java文件中进行引用,代码如下:mButton1 = (Button) findViewById(R.id.button1);mButton1.setOnClickListener(this);//加载xml文件中的动画资源mObjectAnimator = AnimatorInflater.loadAnimator(this, R.animator.translate);mObjectAnimator.setTarget(mButton1);//设置动画的作用对象public void onClick(View v) {switch(v.getId()){case R.id.button1:mObjectAnimator.start();  //开启动画        break;  }}
第二种方式:直接在Java文件中创建并使用动画
mButton1 = (Button) findViewById(R.id.button1);mButton1.setOnClickListener(this);public void onClick(View v) {//利用ofFloat()方法创建动画、指定需要改变的属性的名称等并开启动画ObjectAnimator.ofFloat(mButton1, "translationX", 0.0f,20.0f).setDuration(3000).start();}

简单地说,属性动画就是在指定的时间内改变对象的属性值。

上述的例子,从代码上看,设置了动画执行的时间、作用的目标对象mButton1及其属性translationX以及属性值的初始值和最终值,但从效果上看,mButton1在2秒钟之内在屏幕上匀速的移动了一段距离,于是我们可以猜想:

在start()方法执行之后,是不是会不断地计算出一个值并赋给目标对象的属性? 在属性动画中,是不是也有和补间动画里类似的插值器来改变动画的执行速率? 如果有这样的一个插值器的话,需要赋给目标对象的属性的那个值的计算是不是也和这个插值器有关? ... ... 带着这些猜想,我们就以在Java文件中创建动画的方式为例来梳理属性动画的实现原理。
首先是ObjectAnimator类的静态方法ofFloat /* Constructs and returns an ObjectAnimator that animates between float values. A single value implies that that value is the one being animated to. Two values imply a starting and ending values. More than two values imply a starting value, values to animate through along the way, and an ending value (these values will be distributed evenly across the duration of the animation). 创建并返回 一个基于float类型数值的ObjectAnimator对象,一个value值代表动画的终点,两个value值,则一个是起点, 另一个是终点,如果是多个值, 则中间的值代表动画将要经过的点,并且这些点会均匀地分布在动画的执行过程中 */ public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator (target, propertyName); anim.setFloatValues(values); return anim; }

ObjectAnimator的构造函数:
private ObjectAnimator(Object target, String propertyName) {//为ObjectAnimator的成员变量private Object mTarget赋值,mTarget的注释为://The target object on which the property exists, set in the constructor    mTarget = target;    setPropertyName(propertyName);}
setPropertyName方法:
public void setPropertyName(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.//mValues是ObjectAnimator的父类ValueAnimator的成员变量PropertyValuesHolder[] mValues;//第一次执行为nullif (mValues != null) {        PropertyValuesHolder valuesHolder = mValues[0];        String oldName = valuesHolder.getPropertyName();        valuesHolder.setPropertyName(propertyName);        mValuesMap.remove(oldName);        mValuesMap.put(propertyName, valuesHolder);}//为ObjectAnimator的成员变量private String mPropertyName赋值mPropertyName = propertyName;// New property/values/target should cause re-initialization prior to starting//mInitialized 是ObjectAnimator的父类ValueAnimator的成员变量boolean mInitialized;//它的注释为:Flag that denotes whether the animation is set up and ready to go. //Used to set up animation that has not yet been started.//一个Flag用于标示动画是否开始准备执行,它被用于动画还没有正式开始start之前。默认值为falsemInitialized = false;}
所以, 第一次执行ObjectAnimator anim = new ObjectAnimator(target, propertyName);只做了两件事情: 1、为ObjectAnimator的成员变量mTarget和mPropertyName赋值 2、将mInitialized(定义在ObjectAnimator的父类ValueAnimator 中)的值设为false 接下来是上文中处的anim.setFloatValues(values)方法: @Override public void setFloatValues(float... values) { if (mValues == null || mValues.length == 0) { //第一次执行mValues == null // No values yet - this animator is being constructed piecemeal. Init the values withwhatever the current propertyName is //mValues目前尚未赋值——当前的animator正在构建中,将通过传入的values初始化mValues if (mProperty != null) { //mProperty为ObjectAnimator的成员变量private Property mProperty,第一次执行时也为null setValues( PropertyValuesHolder.ofFloat (mProperty, values)); } else { // 第一次执行时,下列函数将被调用: setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); } } else { super.setFloatValues(values); } }

在分析setValues()方法之前先来看PropertyValuesHolder的ofFloat()方法:

/** * Constructs and returns a PropertyValuesHolder with a given property name andset of float values. */ // 通过给定的propertyName 和 values创建并返回一个PropertyValuesHolder对象 public static PropertyValuesHolder ofFloat(String propertyName, float... values) { return new FloatPropertyValuesHolder(propertyName, values); } 接着FloatPropertyValuesHolder的构造函数:

public FloatPropertyValuesHolder(String propertyName, float... values) { super(propertyName); setFloatValues(values); } 首先执行的是FloatPropertyValuesHolder 的父类 PropertyValuesHolder的构造函数:

private PropertyValuesHolder(String propertyName) {// 为成员变量String mPropertyName(定义在PropertyValuesHolder类中)赋值    mPropertyName = propertyName;}

我们注意到,FloatPropertyValuesHolder、IntPropertyValuesHolder都是PropertyValuesHolder的静态内部类 来看一下PropertyValuesHolder的类定义:
/** * This class holds information about a property and the values that that property should take on during an animation.  * PropertyValuesHolder objects can be used to create animations with ValueAnimator or ObjectAnimator that operate on several     * different properties in parallel. */  //这个类维持着一个property 和它的 值,用以在动画中呈现出来,  //我们可以认为它是为实现属性动画而对property及其值做的一个包装public class PropertyValuesHolder implements Cloneable { }
接下来是上文中处setFloatValues()方法:

@Override public void setFloatValues(float... values) { super.setFloatValues(values); mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; } 首先执行的又是父类的方法:

public void setFloatValues(float... values) { // 为成员变量 ClassmValueType(定义在父类PropertyValuesHolder中)赋值 mValueType = float.class; mKeyframeSet = KeyframeSet.ofFloat(values); }

然后,mKeyframeSet = KeyframeSet.ofFloat(values),先来看KeyframeSet类的定义:

/** * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate * values between those keyframes for a given animation. The class internal to the animation * package because it is an implementation detail of how Keyframes are stored and used. */ //这个类维持着一个Keyframe 对象的集合, //ValueAnimator使用它来为一个动画计算那些 keyframe 之间的值 ... ...class KeyframeSet { }

对KeyframeSet有一个大概了解之后,再来看一下Keyframe类的定义:

/** * This class holds a time/value pair for an animation. The Keyframe class is used by {@link ValueAnimator} to define the values that *  the animation target will have over the course of the animation. As the time proceeds from one keyframe to the other, the value of *  the target object will animate between the value at the previous keyframe and the value at the next keyframe. Each keyframe also  * holds an optional {@link TimeInterpolator} object, which defines the time interpolation over the intervalue preceding the keyframe. */ //简单说,这就是个 对动画过程中的一帧的时间和属性的值进行封装的类public abstract class Keyframe implements Cloneable { }

来看上文中处的KeyframeSet的ofFloat(values)方法:

public static KeyframeSet ofFloat(float... values) { boolean badValue = false;//初始化一个标示, 之后用于标示values[i]是不是一个数字 int numKeyframes = values.length;//获取传入的参数的个数 //初始化一个 FloatKeyframe类型的数组,数组的长度为numKeyframes和2之间的较大者,这个比较容易理解 FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)]; if (numKeyframes == 1) { //如果我们只传入了一个参数,那么这个参数将用于构建 keyframes[1],keyframes[0]的值则由ofFloat(0f)来构建,如下: keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f); // Constructs a Keyframe object with the given time. The value at this time will be derived from the target object when the animation first starts ... ... // 使用给定的time构造一个Keyframe对象,在动画第一次执行时,这个给定的时间对应的value将利用动画的目标对象去获得 ... ... public static Keyframe ofFloat(float fraction) { // FloatKeyframe和IntKeyframe都是Keyframe的静态内部类,这个和PropertyValuesHolder结构是类似的 return new FloatKeyframe(fraction); FloatKeyframe(float fraction) { // 为成员变量float mFraction(定义在 Keyframe)赋值, 注意,在此时,成员变量mValue的值还没有设置 mFraction = fraction; // 为成员变量Class mValueType(定义在Keyframe)赋值 mValueType = float.class; } } keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]); /** * Constructs a Keyframe object with the given time and value. The time defines the time, as a proportion of an overall * animation's duration, at which the value will hold true for the animation ... ... //使用给定的time和value构造一个Keyframe对象,time作为整个动画执行过程中的一个时间比例,是一个0到1之间的值 ... ... public static Keyframe ofFloat(float fraction, float value) { return new FloatKeyframe(fraction, value); FloatKeyframe(float fraction, float value) { mFraction = fraction; mValue = value; mValueType = float.class; mHasValue = true; } } if (Float.isNaN(values[0])) { badValue = true;// 如果传入的值不是一个数值,将标示badValue改为true } //从以上分析可以看到,当我们只传入一个值时,将用1 (代表时间终点)和这个值构建出动画执行的最后一帧的Keyframe // 对象, 而动画的第一帧对应的 Keyframe 对象,则默认由0(代表时间的起点)来构建,这一帧对应的值将在动画第一次 // 执行时由动画 作用的对象来获得,如果我们传入的参数大于1个,比如2个或者多个,则执行下边的逻辑: } else { //逻辑比较简单,如果传入的参数大于1,则,用 0f和values[0]构建出动画的第一帧对应的Keyframe对象并赋值给keyframes[0], //代表第一个value对应动画的起始值 keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]); // 然后,进行遍历,利用 values[i] 和 其所对应的帧在整个动画执行过程中应该处于的时间比例—— //(float) i / (numKeyframes - 1)来构建每一个 Keyframe对象,一般我们传入的参数是两个,所以第二个参数就对应了 // 动画执行的最后一帧的属性值,其实,在这里,属性动画实现的原理已经开始有所体现了。 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; // 同上,如果传入的值不是一个数值,将标示badValue改为true } } } if (badValue) { Log.w("Animator", "Bad value (NaN) in float animator"); // 如果传入的值不是一个数值,执行此逻辑 } //以上逻辑主要就是创建 keyframes数组,该数组中放的是根据传入的value值创建出来的动画执行过程中的关键帧对象 //即 (主要是) 将一个 mKeyframes成员变量完成初始化的FloatKeyframeSet对象返回 return new FloatKeyframeSet(keyframes); public FloatKeyframeSet(FloatKeyframe... keyframes) { // 走的是父类的构造函数 super(keyframes); public KeyframeSet(Keyframe... keyframes) { //这个逻辑就比较简单了 mNumKeyframes = keyframes.length;//为成员变量int mNumKeyframes()赋值 mKeyframes = new ArrayList<Keyframe>(); //将接收到的 keyframes数组中的元素添加到 成员变量ArrayList<Keyframe> mKeyframes集合中 mKeyframes.addAll(Arrays.asList(keyframes)); mFirstKeyframe = mKeyframes.get(0);// 初始化第一帧对应的成员变量Keyframe mFirstKeyframe mLastKeyframe = mKeyframes.get(mNumKeyframes - 1); // 初始化最后一帧对应的成员变量KeyframemLastKeyframe // 初始化插值器对应的成员变量TimeInterpolator mInterpolator,目前为null mInterpolator = mLastKeyframe.getInterpolator(); private TimeInterpolator mInterpolator = null; public TimeInterpolator getInterpolator() { return mInterpolator; } } } }

至此,KeyframeSet的ofFloat(values)方法完成了,主要的逻辑是:

根据传入的value值创建出动画执行过程中的关键帧对象,将这些对象放在一个数组中,new一个FloatKeyframeSet对象,然后将数组中的这些元素,放在FloatKeyframeSet对象的成员变量ArrayList<Keyframe> mKeyframes中,并将FloatKeyframeSet对象返回。
上边第步将这个FloatKeyframeSet对象赋值给PropertyValuesHolder的成员变量KeyframeSet mKeyframeSet,于是,第步也执行完了,接着,在setFloatValues()方法中,执行完第步后:
mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;//将mKeyframeSet向下转型为FloatKeyframeSet赋值给FloatPropertyValuesHolder//的成员变量FloatKeyframeSet mFloatKeyframeSet

于是,第步也执行完了,第步把完成初始化的FloatPropertyValuesHolder对象返回,第步将利用第步返回的对象作为参数,执行setValues()方法,(该方法在ObjectAnimator的父类ValueAnimator类中定义),具体逻辑如下:

public void setValues(PropertyValuesHolder... values) {    int numValues = values.length;    // 为PropertyValuesHolder[] mValues(在ObjectAnimator父类ValueAnimator中定义)赋值    mValues = values;// 为成员变量HashMap<String, PropertyValuesHolder> mValuesMap赋值,//以下是关于mValuesMap的注释://A hashmap of the PropertyValuesHolder objects. This map is used to lookup //animated values by property name during calls to getAnimatedValue(String).//一个用于存储PropertyValuesHolder对象的集合,在调用getAnimatedValue(String)方法//时通过property name来查找values     mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);    for (int i = 0; i < numValues; ++i) {        PropertyValuesHolder valuesHolder = values[i];        mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);    }    // New property/values/target should cause re-initialization prior to starting    mInitialized = false;}


至此,用于创建属性动画对象的ObjectAnimator类的静态方法ofFloat的大体逻辑分析完成了。简单总结一下: ObjectAnimator.ofFloat(Object target, String propertyName, float... values)创建了一个ObjectAnimator对象,并且: 1、将target 赋给 ObjectAnimator 的成员变量 private Object mTarget 2、将 propertyName 赋给 ObjectAnimator 的成员变量 private String mPropertyName 3、创建一个 FloatPropertyValuesHolder 对象 3.1、将 propertyName 赋给 FloatPropertyValuesHolder 的 成员变量 String mPropertyName(在 FloatPropertyValuesHolder 的父 PropertyValuesHolder中定义 3.2、 float.class赋给 FloatPropertyValuesHolder 的 成员变量Class mValueType(在 FloatPropertyValuesHolder 的父 PropertyValuesHolder中定义 3.3、创建一个FloatKeyframeSet对象 3.3.1、创建一个 FloatKeyframe 类型的数组 keyframes 3.3.2、根据传入的 values 构造出 keyframes 数组中的每一项(关键帧对象 Keyframe 3.3.3、将 keyframes 数组中的每一项添加到 FloatKeyframeSet 对象的成员变量 ArrayList<Keyframe>mKeyframes(在 FloatKeyframeSet 的父类 KeyframeSet中定义 )中 3.4、将 FloatKeyframeSet 对象 赋给 PropertyValuesHolder 的成员变量 KeyframeSet mKeyframeSet 3.5、将mKeyframeSet 向下转型为FloatKeyframeSet 类型赋给 FloatPropertyValuesHolder 的成员变量FloatKeyframeSet mFloatKeyframeSet 4、 FloatPropertyValuesHolder 对象赋给ObjectAnimator 的成员变量PropertyValuesHolder[] mValues (在 ObjectAnimator 的父类 ValueAnimator中定义 5、利用已完成初始化的 FloatPropertyValuesHolder 对象及其 mPropertyName属性, 完成成员变量HashMap<String, PropertyValuesHolder> mValuesMap(在ValueAnimator中定义 )的 初始化
动画开始执行之前,还有一个关键的方法 —setDuration(long) public ObjectAnimator setDuration(long duration) { // 执行的是父类ValueAnimator 的setDuration()方法 super.setDuration(duration); private static float sDurationScale = 1.0f; // How long the animation should last in ms 默认时间是300毫秒 private long mDuration = (long)(300 * sDurationScale); private long mUnscaledDuration = 300; public ValueAnimator setDuration(long duration) { if (duration < 0) { // 若传入的值小于零,抛出异常 throw new IllegalArgumentException("Animators cannot have negative duration: " + duration); } mUnscaledDuration = duration; mDuration = (long)(duration * sDurationScale); return this; } return this; }
另外,在setDuration( )方法中,我们可以看到 成员变量 mDuration 的值最终是由我们调用setDuration( )方法时传入的duration 乘以sDurationScale 得出的,sDurationScale 默认值为1.0f ; 并且 ValueAnimator 类中提供了静态方法 setDurationScale() 供我们使用 public static void setDurationScale(float durationScale) { sDurationScale = durationScale; } 我们可以利用这个方法改变动画的速度

下边来看属性动画的执行过程 —— start( )方法
从上文的分析,我们注意到,使用ObjectAnimator类的静态方法ofFloat来创建动画对象的过程中,ObjectAnimator类只是复写了父类ValueAnimator的一部分方法,同样也只拥有部分只属于自己的成员变量,事实上,我们在使用属性动画时,所涉及到的类的继承关系如下:
/** * This is the superclass for classes which provide basic support for animations which can be * started, ended, and have <code>AnimatorListeners</code> added to them. */ //这是那些为动画提供最基础的支持以让动画能被开启、结束和被增加监听的类的超类public abstract class Animator implements Cloneable { }
Animator 是属性动画体系的超类,它定义了诸如start()、cancel()、end()、setDuration(long duration)、setInterpolator(TimeInterpolator value)、isRunning()、addListener(AnimatorListener listener)、removeAllListeners() 等方法 AnimatorSet 在属性动画中的用法和在补间动画中类似,不细讲了 ValueAnimator 和ObjectAnimator 是属性动画的实现类,它们的区别在哪里?分析完start( ) 方法,再结合上边的ofFloat( ) 方法进行总结
ObjectAnimator 的start() 方法:
public void start() {    // See if any of the current active/pending animators need to be canceled    AnimationHandler handler = sAnimationHandler.get();    if (handler != null) { ... ... } // 第一次进入这里 handler 应该是 null    super.start(); // 执行父类的start()方法}
ValueAnimator 的start() 方法: public void start() { start(false); } /** * Start the animation playing. This version of start() takes a boolean flag that indicates whether the animation should play in * reverse. The flag is usually false, but may be set to true if called from the reverse() method. * <p>The animation started by calling this method will be run on the thread that called this method. This thread should have * a Looper on it (a runtime exception will be thrown if this is not the case). Also, if the animation will animate properties of * objects in the view hierarchy, then the calling thread should be the UI thread for that view hierarchy.</p> */ // 开始执行动画,这个 start()方法 有一个boolean型的参数用于标示该动画是否需要反转,该参数 一般 为false,但是也可能 // 被设置为true如果start()方法是从reverse()方法中调用的,该动画将运行在调用start()方法的线程里,这个线程需要拥有 // 一个 Looper 对象,否则会发生异常 ... ... private void start(boolean playBackwards) { if (Looper.myLooper() == null) { throw new AndroidRuntimeException("Animators may only be run on Looper threads"); } mPlayingBackwards = playBackwards;// 动画是否反转的标示 //This variable tracks the current iteration that is playing. When mCurrentIteration exceeds therepeatCount //(if repeatCount!=INFINITE), the animation ends这个变量用于记录当前动画的循环次数,当mCurrentIteration超过了 //repeatCount(如果repeatCount 不等于 -1),动画将被终止,该变量默认值为0 mCurrentIteration = 0; mPlayingState = STOPPED;//标示动画的状态,以下是ValueAnimator中对动画状态的定义: /** * Values used with internal variable mPlayingState to indicate the current state of ananimation. */ // 变量mPlayingState使用这些值来标示动画的状态 static final int STOPPED = 0;// Not yet playing 尚未开始 static final int RUNNING = 1;// Playing normally 正常进行中 static final int SEEKED = 2; // Seeked to some time value mStarted = true; //Tracks whether a startDelay'd animation has begun playing through the startDelay. mStartedDelay = false; //Whether this animator is currently in a paused state. mPaused = false; AnimationHandler animationHandler = getOrCreateAnimationHandler(); private static AnimationHandler getOrCreateAnimationHandler() { AnimationHandler handler = sAnimationHandler.get(); if (handler == null) {// 第一次执行,走下边的逻辑 handler = new AnimationHandler(); sAnimationHandler.set(handler);// 此处涉及ThreadLocal的使用,暂不细说 } return handler; } // 将此动画对象添加到AnimationHandler的mPendingAnimations集合中 animationHandler.mPendingAnimations.add(this); if (mStartDelay == 0) { // The amount of time in ms to delay starting the animation after start() is called 调用start()方法之后延迟多少时间播放动画 private long mStartDelay = 0;// 默认为零,执行下边的逻辑 // This sets the initial value of the animation, prior to actually starting it running setCurrentPlayTime(0); mPlayingState = STOPPED; mRunning = true; notifyStartListeners(); } animationHandler.start(); } 在ValueAnimator的start( )方法中,需要重点分析的就是setCurrentPlayTime(0)和animationHandler.start()这两个方法 setCurrentPlayTime(0)方法: public void setCurrentPlayTime(long playTime) { initAnimation(); long currentTime = AnimationUtils.currentAnimationTimeMillis(); if (mPlayingState != RUNNING) { mSeekTime = playTime; mPlayingState = SEEKED; } mStartTime = currentTime - playTime; doAnimationFrame(currentTime); } 上边处的initAnimation()方法: //ObjectAnimator 复写了父类的initAnimation()方法 void initAnimation() { if (!mInitialized) {// 此时 mInitialized的值为false,执行下边逻辑 // mValueType may change due to setter/getter setup; do this before calling super.init(), // which uses mValueType to set up the default type evaluator. int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { mValues[i].setupSetterAndGetter(mTarget); } super.initAnimation(); } } 上边第步执行的是PropertyValuesHolder的setupSetterAndGetter()方法,来看具体逻辑:
void setupSetterAndGetter(Object target) {    if (mProperty != null) {        // check to make sure that mProperty is on the class of target        try {            Object testValue = mProperty.get(target);            for (Keyframe kf : mKeyframeSet.mKeyframes) {                if (!kf.hasValue()) {                    kf.setValue(mProperty.get(target));                }            }            return;        } catch (ClassCastException e) {            Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +                    ") on target object " + target + ". Trying reflection instead");            mProperty = null;        }    }    // 从上文中属性动画的创建的分析来看,此时的mProperty 为null,从下边开始执行    Class targetClass = target.getClass();    if (mSetter == null) {    // PropertyValuesHolder 的成员变量 Method mSetter,默认为null        setupSetter(targetClass);    }    for (Keyframe kf : mKeyframeSet.mKeyframes) {        if (!kf.hasValue()) {            if (mGetter == null) {                setupGetter(targetClass);                if (mGetter == null) {                // PropertyValuesHolder 的成员变量 private Method mGetter,默认为null                    // Already logged the error - just return to avoid NPE                    return;                }            }            try {                kf.setValue(mGetter.invoke(target));            } catch (InvocationTargetException e) {                Log.e("PropertyValuesHolder", e.toString());            } catch (IllegalAccessException e) {                Log.e("PropertyValuesHolder", e.toString());            }        }    }}
setupSetterAndGetter()方法中,重点分析setupSetter(targetClass)、setupGetter(targetClass)以及kf.setValue(mGetter.invoke(target))方法 setupSetter(targetClass)方法
void setupSetter(Class targetClass) {// 可以看到,该方法的主要作用就是给PropertyValuesHolder 的成员变量 Method mSetter 赋值    mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);}
setupGetter(Class targetClass)方法
private void setupGetter(Class targetClass) {// 可以看到,该方法的主要作用就是给 PropertyValuesHolder 的成员变量 Method mGetter 赋值    mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);}
setupSetter(targetClass) 和 setupGetter(targetClass) 方法都调用了 setupSetterOrGetter 方法,只是参数有所不同,第一个和第三个好理解,第二个参数是一个集合,其定义如下:
//These maps hold all property entries for a particular class. This map is used to speed up property/setter/getter lookups for a given //class/property combination. No need to use reflection on the combination more than once. 也比较简单明了private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap =         new HashMap<Class, HashMap<String, Method>>();private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap =         new HashMap<Class, HashMap<String, Method>>();
第四个参数,对于 setupSetter()方法来讲,传入的是mValueType( 我们在创建动画对象时已为其赋值 ),而对于setupGetter()方法来讲,传入的是null,来看setupSetterOrGetter 方法的主要逻辑:
/** * Returns the setter or getter requested. This utility function checks whether the requested method exists in the propertyMapMap * cache. If not, it calls another utility function to request the Method from the targetClass directly. */ // 首先看注释,检查propertyMapMap集合是否有所请求的 setter or getter 方法,如果有,返回,如果没有,通过targetClass // 获得他们,将它们缓存起来并返回private Method setupSetterOrGetter(Class targetClass,        HashMap<Class, HashMap<String, Method>> propertyMapMap,        String prefix, Class valueType) {    Method setterOrGetter = null; // 定义临时变量    try {        // 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        mPropertyMapLock.writeLock().lock();        HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);        if (propertyMap != null) {// 第一次执行,此处propertyMap 为 null            setterOrGetter = propertyMap.get(mPropertyName);        }        if (setterOrGetter == null) {// Determine the setter or getter function using the JavaBeans convention of setFoo or getFoo for a property // named 'foo'. This function figures out what the name of the function should be and uses reflection to find the Method // with that name on the target object.利用反射获取set和get方法            setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);            if (propertyMap == null) {                propertyMap = new HashMap<String, Method>();                propertyMapMap.put(targetClass, propertyMap);            }            // 将获得的方法缓存起来            propertyMap.put(mPropertyName, setterOrGetter);        }    } finally {        mPropertyMapLock.writeLock().unlock();    }    return setterOrGetter;}
setupSetterAndGetter()方法中 ,setupSetter(targetClass)、setupGetter(targetClass)方法大致分析完了,它完成了对mSetter和mGetter的初始化,接下来,对KeyframeSet的成员变量ArrayList<Keyframe> mKeyframes (上文分析过,在属性动画的对象创建时,就以完成对mKeyframes的初始化,mKeyframes里边放的是根据传入的value构造出的动画执行过程中的帧对象) 进行遍历,具体逻辑是: for (Keyframe kf : mKeyframeSet.mKeyframes) { if (!kf.hasValue()) {// hasValue()方法定义如下: public boolean hasValue() { return mHasValue;//Keyframe的成员变量, boolean mHasValue ,默认是 false // 上文我们在讲动画创建过程中 根据传入的 values 构造出keyframes 数组中的每一项(关键帧对象Keyframe)时,已经讲过, // 如果我们只传入了一个参数,那么这个参数将用于构建 keyframes[1],走下边的第一个构造函数 //keyframes[0]的值则由ofFloat(0f)来构建,走下边的第二个构造函数,即此关键帧对象的mHasValue为默认值false FloatKeyframe(float fraction, float value) { mFraction = fraction; mValue = value; mValueType = float.class; mHasValue = true;// 标示一个帧对象是否已有value值 } FloatKeyframe(float fraction) { mFraction = fraction; mValueType = float.class; } } if (mGetter == null) { setupGetter(targetClass);// 上文已分析过了 if (mGetter == null) { // Already logged the error - just return to avoid NPE return; } } try { kf.setValue(mGetter.invoke(target)); // 该方法利用通过反射获得的get方法为mKeyframes集合中还没有value值的帧对象赋值 // 上文中,讲到 Keyframe 对象的创建时,构造函数 public static Keyframe ofFloat(float fraction)的注释为: // Constructs a Keyframe object with the given time. The value at this time will be derived from the target object when // the animation first starts ... ... 指的就是这个地方 public void setValue(Object value) { if (value != null && value.getClass() == Float.class) { mValue = ((Float)value).floatValue(); mHasValue = true; } } } catch (InvocationTargetException e) { Log.e("PropertyValuesHolder", e.toString()); } catch (IllegalAccessException e) { Log.e("PropertyValuesHolder", e.toString()); } } }
至此,上边第步执行完了,它主要是对动画对象的成员变量PropertyValuesHolder[] mValues做更进一步的初始化,接下来执行上文中的第步,父类ValueAnimator中定义的initAnimation()方法 /** * This function is called immediately before processing the first animationframe of an animation. If there is a nonzero * <code>startDelay</code>, thefunction is called after that delay ends.It takes care of the final initialization steps for the *animation. ... ... */ // 这个方法在执行动画的第一帧之前被调用,如果有一个不为零的startDelay值,该方法将在相应的延迟时间执后被执行 // 这是一个动画最后的初始化步骤 ... ... void initAnimation() { if (!mInitialized) { int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { mValues[i].init(); /** * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used tocalculate animated values. */ // 逻辑很简单,就是根据mValueType的值设置成员变量TypeEvaluator mEvaluator 的值,用来 calculate animated values 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 mKeyframeSet.setEvaluator(mEvaluator); } } } // 现在,动画最后的初始化已经完成,就将 mInitialized 的值设为 true 了 mInitialized = true; } }
到现在,上文中第步也完成了,我们可以看到,这一步是在做进一步的初始化,其中对set和get方法的初始化和为没有value值得帧对象赋值的操作是在ObjectAnimator中完成的,而对用来计算动画的value值的TypeEvaluator的初始化则是在ValueAnimator中完成的
稍后再来分析上文中第步的doAnimationFrame(currentTime)方法,因此,在ValueAnimator的start( )方法中,需要重点分析的两个方法之一setCurrentPlayTime(0)就到此为止,接着看后边的animationHandler.start(): animationHandler.start()方法最终会导致AnimationHandler的run方法的执行(此处细节省略):
public void run() {    mAnimationScheduled = false;    // 这是AnimationHandler类中的doAnimationFrame()方法    doAnimationFrame(mChoreographer.getFrameTime());}
doAnimationFrame( )方法: private void doAnimationFrame(long frameTime) { // mPendingAnimations holds any animations that have requested to be started // We're going to clear mPendingAnimations, but starting animation may // cause more to be added to the pending list (for example, if one animation // starting triggers another starting). So we loop until mPendingAnimations is empty. while (mPendingAnimations.size() > 0) { ArrayList<ValueAnimator> pendingCopy = (ArrayList<ValueAnimator>) mPendingAnimations.clone(); mPendingAnimations.clear(); int count = pendingCopy.size(); for (int i = 0; i < count; ++i) { ValueAnimator anim = pendingCopy.get(i); // If the animation has a startDelay, place it on the delayed list if (anim.mStartDelay == 0) { anim.startAnimation(this); // 其实,上述代码最主要的就是执行了一句handler.mAnimations.add(this); } else { mDelayedAnims.add(anim); } } } // Next, process animations currently sitting on the delayed queue, adding them to the active animations if they are ready int numDelayedAnims = mDelayedAnims.size(); for (int i = 0; i < numDelayedAnims; ++i) { ValueAnimator anim = mDelayedAnims.get(i); if (anim.delayedAnimationFrame(frameTime)) { mReadyAnims.add(anim); } } int numReadyAnims = mReadyAnims.size(); if (numReadyAnims > 0) { for (int i = 0; i < numReadyAnims; ++i) { ValueAnimator anim = mReadyAnims.get(i); anim.startAnimation(this); anim.mRunning = true; mDelayedAnims.remove(anim); } mReadyAnims.clear(); } //Now process all active animations. The return value from animationFrame() tells the handler whether it should now be ended int numAnims = mAnimations.size(); for (int i = 0; i < numAnims; ++i) { mTmpAnimations.add(mAnimations.get(i)); } for (int i = 0; i < numAnims; ++i) { ValueAnimator anim = mTmpAnimations.get(i); if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime) ) { mEndingAnims.add(anim); } } mTmpAnimations.clear(); if (mEndingAnims.size() > 0) { for (int i = 0; i < mEndingAnims.size(); ++i) { mEndingAnims.get(i).endAnimation(this); } mEndingAnims.clear(); } // If there are still active or delayed animations, schedule a future call to onAnimate to process the next frame of the animations. if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) { scheduleAnimation(); } } 可以看到,在AnimationHandler类中,有以下几个集合:
//The per-thread list of all active animationsprotected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();//Used in doAnimationFrame() to avoid concurrent modifications of mAnimationsprivate final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();//The per-thread set of animations to be started on the next animation frameprotected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
在AnimationHandler类的doAnimationFrame( )方法中,会根据动画的属性值的变化,用这些集合来管理动画对象,并且在这个过程中,会调用到最核心的ValueAnimator类的doAnimationFrame()方法(第步)当mAnimations.contains(anim)并且doAnimationFrame()方法的返回值为true时,就会执行mEndingAnims.add(anim);将动画对象添加到mEndingAnims集合中,接着,遍历mEndingAnims集合,执行mEndingAnims.get(i).endAnimation(this);主要是将mAnimations、mPendingAnimations、mDelayedAnims集合中的对象清空以及改变一些标示。标示着动画的结束。 如果doAnimationFrame()方法的返回值为false, 则在满足条件(!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())时,执行scheduleAnimation(),即相当于调用animationHandler.start()继续循环。
那么doAnimationFrame()方法的逻辑是什么? 又回到了在上文中,当时我们暂时放下没有分析的第步中的doAnimationFrame(currentTime)方法上:
final boolean doAnimationFrame(long frameTime) {    if (mPlayingState == STOPPED) {   }    if (mPaused) {}    else if (mResumed) {     }    // 主要是下边的代码    final long currentTime = Math.max(frameTime, mStartTime);    return animationFrame(currentTime);}
接着是 animationFrame()方法: boolean animationFrame(long currentTime) { boolean done = false; switch (mPlayingState) { case RUNNING: case SEEKED: float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; if (fraction >= 1f) { if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { // Time to repeat if (mListeners != null) { int numListeners = mListeners.size(); for (int i = 0; i < numListeners; ++i) { mListeners.get(i).onAnimationRepeat(this); } } if (mRepeatMode == REVERSE) { mPlayingBackwards = !mPlayingBackwards; } mCurrentIteration += (int)fraction; fraction = fraction % 1f; mStartTime += mDuration; } else { done = true; fraction = Math.min(fraction, 1.0f); } } if (mPlayingBackwards) { fraction = 1f - fraction; } animateValue(fraction); break; } return done; } 我们看到,在每一次调用该方法时,都会根据动画对象的一些和时间相关的属性的值来计算fraction的值,来判断要返回true还是false。 从代码中,可以看出,fraction代表的就是动画执行过程中的每一帧在整个动画执行过程中所处的时间的比率。
分析到此,整个属性动画的实现原理基本清楚了,还剩最后一点 —— 每一次调用animationFrame方法时,怎么利用计算出来的fraction来改变动画作用对象的属性值以达到动画的效果?答案是上文中处的animateValue(fraction)方法,需要注意的是,ObjectAnimator类重写了父类的animateValue(fraction)方法,来看具体逻辑: void animateValue(float fraction) { super.animateValue(fraction);// 首先调用父类的方法 int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { mValues[i].setAnimatedValue(mTarget); 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()); } } } } } 父类ValueAnimator的animateValue(fraction)方法: void animateValue(float fraction) { // 此时,我们在文章的开头提到的插值器登场了 fraction =mInterpolator.getInterpolation(fraction); private TimeInterpolatormInterpolator=sDefaultInterpolator; private static final TimeInterpolatorsDefaultInterpolator=new AccelerateDecelerateInterpolator(); // 可以看到,如果不进行设置的话,默认的插值器就是AccelerateDecelerateInterpolator 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); } } }

至此,属性动画实现原理基本清楚了。


更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Android完全退出应用程序的方法
  5. view-ListView学习
  6. [置顶] Android资源文件分析
  7. Android欢迎界面的创建方法
  8. android 设置全屏的两种方法
  9. Android启动画面实现

随机推荐

  1. 一个APK反编译利器Apktool(android汉化)
  2. Android(安卓)Root方法原理解析及Hook(一
  3. Android菜鸟日记31-selector 中使用 shap
  4. [Android实例] Android网络收音机项目(内
  5. android 工程 日志输出 附源码
  6. 我的hosts文件
  7. android:屏幕自适应
  8. android 应用层开发
  9. Android之发送短信和接收验证码
  10. Android(安卓)开发环境的搭建