首页 > 代码库 > Android - Animation(二)
Android - Animation(二)
Android - Animation(一) 一文总结了Android中的补间动画(View Animation/Tween Animation)和帧动画(Drawable Animation/Frame Animation)的使用
本篇文章主要解析属性动画(Property Animation,android3.0引入)的实现原理
下篇 属性动画的实现原理
先来看属性动画的最简单实现:
- // 首先在/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;
- }
- }
- 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秒钟之内在屏幕上匀速的移动了一段距离。于是我们能够猜想:
- 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);
- }
- 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;
- //第一次运行为null
- if (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之前。
默认值为false
- mInitialized = false;
- }
在分析setValues()方法之前先来看PropertyValuesHolder的ofFloat()方法:
- private PropertyValuesHolder(String propertyName) {
- // 为成员变量String mPropertyName(定义在PropertyValuesHolder类中)赋值
- mPropertyName = propertyName;
- }
- /**
- * 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 { }
然后,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)方法:
至此,KeyframeSet的ofFloat(values)方法完毕了,基本的逻辑是:
- 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;
- }
简单总结一下:
- /**
- * 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 { }
- 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()方法
- }
- 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());
- }
- }
- }
- }
- void setupSetter(Class targetClass) {
- // 能够看到,该方法的主要作用就是给PropertyValuesHolder 的成员变量 Method mSetter 赋值
- mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
- }
- private void setupGetter(Class targetClass) {
- // 能够看到,该方法的主要作用就是给 PropertyValuesHolder 的成员变量 Method mGetter 赋值
- mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
- }
- //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>>();
- /**
- * 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;
- }
sFloatEvaluator :
- public void run() {
- mAnimationScheduled = false;
- // 这是AnimationHandler类中的doAnimationFrame()方法
- doAnimationFrame(mChoreographer.getFrameTime());
- }
- //The per-thread list of all active animations
- protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
- //Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
- private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
- //The per-thread set of animations to be started on the next animation frame
- protected 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>();
- final boolean doAnimationFrame(long frameTime) {
- if (mPlayingState == STOPPED) { }
- if (mPaused) { }
- else if (mResumed) { }
- // 主要是下边的代码
- final long currentTime = Math.max(frameTime, mStartTime);
- return animationFrame(currentTime);
- }
Android - Animation(二)