Android - Animation(一) 一文总结了Android中的补间动画(View Animation/Tween Animation)和帧动画(Drawable Animation/Frame Animation)的使用java
本篇文章主要解析属性动画(Property Animation,android3.0引入)的实现原理android
下篇 属性动画的实现原理数组
先来看属性动画的最简单实现:缓存
第一种方式:先在 /res/animator/文件夹下建立translate.xml文件定义动画。再在Java文件里引用并开启
-
- <?
xml version="1.0" encoding="utf-8"?ide
> 函数
- <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>
-
-
- mButton1 = (Button) findViewById(R.id.button1);
- mButton1.setOnClickListener(this);
-
- 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) {
-
- ObjectAnimator.ofFloat(mButton1, "translationX", 0.0f,20.0f).setDuration(3000).start();
- }
简单地说,属性动画就是在指定的时间内改变对象的属性值。oop
上述的样例。从代码上看,设置了动画运行的时间、做用的目标对象mButton1及其属性translationX以及属性值的初始值和终于值,但从效果上看,mButton1在2秒钟以内在屏幕上匀速的移动了一段距离。因而咱们可以猜测:post
在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) {
-
-
- mTarget = target;
- setPropertyName(propertyName);
- }
setPropertyName方法:
- public void setPropertyName(String propertyName) {
-
-
-
-
- if (mValues != null) {
- PropertyValuesHolder valuesHolder = mValues[0];
- String oldName = valuesHolder.getPropertyName();
- valuesHolder.setPropertyName(propertyName);
- mValuesMap.remove(oldName);
- mValuesMap.put(propertyName, valuesHolder);
- }
-
- mPropertyName = propertyName;
-
-
-
-
-
- mInitialized = false;
- }
因此。
第一次运行ObjectAnimator anim = new ObjectAnimator(target, propertyName);仅仅作了两件事情:
一、为ObjectAnimator 的成员变量mTarget和mPropertyName赋值
二、将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 with whatever 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()方法:ui
/**
* Constructs and returns a PropertyValuesHolder with a given property name and set 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) {
-
- mPropertyName = propertyName;
- }
咱们注意到,FloatPropertyValuesHolder 、IntPropertyValuesHolder都是PropertyValuesHolder的静态内部类
来看一下PropertyValuesHolder的类定义:
-
-
-
-
-
-
-
- public class PropertyValuesHolder implements Cloneable { }
接下来是上文中❹处setFloatValues()方法:
@Override
public void setFloatValues(float... values) {
❺
super.setFloatValues(values);
mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
}
首先运行的又是父类的方法:
public void setFloatValues(float... values) {
// 为成员变量
Class mValueType(定义在父类PropertyValuesHolder中)赋值
mValueType = float.class;
❻
mKeyframeSet = KeyframeSet.ofFloat(values);
}
而后,mKeyframeSet = KeyframeSet.ofFloat(values),先来看KeyframeSet类的定义:
对KeyframeSet有一个大概了解以后。再来看一下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之间的较大者,这个比較easy理解
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);
// 初始化最后一帧相应的成员变量Keyframe mLastKeyframe
// 初始化插值器相应的成员变量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;
-
-
因而。第❹步也运行完了,第❸步把完毕初始化的FloatPropertyValuesHolder对象返回,第❷步将利用第❸步返回的对象做为參数。运行setValues()方法。(该方法在ObjectAnimator的父类ValueAnimator类中定义),详细逻辑例如如下:
- public void setValues(PropertyValuesHolder... values) {
- int numValues = values.length;
-
- mValues = values;
-
-
-
-
-
-
- mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
- for (int i = 0; i < numValues; ++i) {
- PropertyValuesHolder valuesHolder = values[i];
- mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
- }
-
- mInitialized = false;
- }
至此,用于建立属性动画对象的ObjectAnimator类的静态方法ofFloat的大致逻辑分析完毕了。简单总结一下:
ObjectAnimator.ofFloat(Object target, String propertyName, float... values) 建立了一个ObjectAnimator对象,并且:
一、将 target 赋给 ObjectAnimator 的成员变量
private Object mTarget
二、将
propertyName 赋给
ObjectAnimator 的成员变量
private String mPropertyName
三、建立一个 FloatPropertyValuesHolder 对象
3.一、将
propertyName 赋给
FloatPropertyValuesHolder 的
成员变量
String mPropertyName(在
FloatPropertyValuesHolder
的父类
PropertyValuesHolder中定义
)
3.二、
将
float.class 赋给
FloatPropertyValuesHolder 的
成员变量 Class mValueType(在
FloatPropertyValuesHolder
的父类
PropertyValuesHolder中定义
)
3.三、建立一个 FloatKeyframeSet对象
3.3.一、建立一个 FloatKeyframe 类型的数组 keyframes
3.3.二、依据传入的 values 构造出
keyframes 数组中的每一项(关键帧对象
Keyframe
)
3.3.三、将
keyframes 数组中的每一项加入到
FloatKeyframeSet 对象的成员变量
ArrayList<Keyframe>mKeyframes(在
FloatKeyframeSet
的父类
KeyframeSet中定义
)中
3.四、将
FloatKeyframeSet 对象
赋给
PropertyValuesHolder 的成员变量
KeyframeSet mKeyframeSet
3.五、将 mKeyframeSet 向下转型为 FloatKeyframeSet 类型赋给
FloatPropertyValuesHolder 的成员变量 FloatKeyframeSet mFloatKeyframeSet
四、将
FloatPropertyValuesHolder 对象 赋给ObjectAnimator 的成员变量 PropertyValuesHolder[] mValues
(在
ObjectAnimator
的父类
ValueAnimator中定义
)
五、利用已完毕初始化的
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的一部分方法,相同也仅仅拥有部分仅仅属于本身的成员变量,其实。咱们在使用属性动画时。所涉及到的类的继承关系例如如下:
-
-
-
-
-
- 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() {
-
- AnimationHandler handler = sAnimationHandler.get();
- if (handler != null) { ... ... }
- super.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 the repeatCount
// (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 an animation.
*/
// 变量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) {
-
- 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;
- }
- }
-
- Class targetClass = target.getClass();
- if (mSetter == null) {
-
- setupSetter(targetClass);
- }
- for (Keyframe kf : mKeyframeSet.mKeyframes) {
- if (!kf.hasValue()) {
- if (mGetter == null) {
- setupGetter(targetClass);
- if (mGetter == null) {
-
-
- 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) {
-
- mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
- }
setupGetter(Class targetClass)方法
- private void setupGetter(Class targetClass) {
-
- mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
- }
setupSetter(targetClass) 和 setupGetter(targetClass) 方法都调用了
setupSetterOrGetter 方法,仅仅是參数有所不一样,第一个和第三个好理解,第二个參数是一个集合,其定义例如如下:
-
-
- 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 方法的主要逻辑:
-
-
-
-
-
-
- private Method setupSetterOrGetter(Class targetClass,
- HashMap<Class, HashMap<String, Method>> propertyMapMap,
- String prefix, Class valueType) {
- Method setterOrGetter = null;
- try {
-
-
-
- mPropertyMapLock.writeLock().lock();
- HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
- if (propertyMap != null) {
- setterOrGetter = propertyMap.get(mPropertyName);
- }
- if (setterOrGetter == null) {
-
-
-
- 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 animation frame of an animation. If there is a nonzero
* <code>startDelay</code>, the function 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
to calculate animated values.
*/
// 逻辑很是easy。就是依据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;
-
- 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类中。有下面几个集合:
-
- protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
-
- private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
-
- 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>();
在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 TimeInterpolator mInterpolator = sDefaultInterpolator;
private static final TimeInterpolator sDefaultInterpolator = 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);
}
}
}
至此,属性动画实现原理基本清楚了。