如果文章有问题,请及时指出
文中源码都来自android28
整体流程
ObjectAnimator.start()
-> ValueAnimator.start()
-> ValueAnimator.addAnimationCallback()
-> AnimationHandler.addAnimationFrameCallback()
-> MyFrameCallbackProvider.postFrameCallback()
-> Choreographer.postFrameCallback(callback); // 请求Vsync信号
// Vsync信号到了
-> Choreographer.doFrame()
-> Choreographer.doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
-> AnimationHandler.doAnimationFrame()
-> ValueAnimator.doAnimationFrame()
-> ValueAnimator.animateBasedOnTime()
-> ObjectAnimator.animateValue()
-> valueAnimator.animateValue(currentIterationFraction) // 使用插值器计算属性值变化比例(百分比)
-> PropertyValuesHolder.calculateValue(fraction) // 使用估值器计算最终值
-> AnimatorUpdateListener.onAnimationUpdate(this) // 通知监听更新值
-> PropertyValuesHolder.setAnimatedValue(target) // 使用seter修改属性值
插值器:
插值器其实是变化快慢的一个衡量标准,根据时间流逝的比例,来得出属性变化的比例。可能返回小于0或者大于1的值。
当前时间流逝百分比 -> 当前属性变化的比例 控制变化速率
估值器:
属性变化的比例 -> 动画当前具体值 计算具体值
ObjectAnimator
ObjectAnimator通过重写ValueAnimator中的animateValue()方法,修改属性值的。
void animateValue(float fraction) {
final Object target = getTarget();
if (mTarget != null && target == null) {
// We lost the target reference, cancel and clean up. Note: we allow null target if the
/// target has never been set.
cancel();
return;
}
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
// 修改属性值
mValues[i].setAnimatedValue(target);
}
}
ValueAnimator
ValueAnimator.java
PropertyValuesHolder[] mValues; // 记录属性名,会反射调用修改属性值
private void start(boolean playBackwards) {
......
// 会请求Choreographer
addAnimationCallback(0);
......
}
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
// Choreographer垂直同步信号到时,会调用这个方法
public final boolean doAnimationFrame(long frameTime) {
.....
// 计算动画数值
boolean finished = animateBasedOnTime(currentTime);
.....
}
boolean animateBasedOnTime(long currentTime) {
.......
animateValue(currentIterationFraction);
.......
}
void animateValue(float fraction) {
// 使用插值器计算进度
fraction = mInterpolator.getInterpolation(fraction);
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);
}
}
}
AnimationHandler
与Choreographer通信,请求Vsync信号
AnimationHandler.java
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
// 执行当前帧动画
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
// 请求下一个Vsync
getProvider().postFrameCallback(this);
}
}
};
PropertyValuesHolder
PropertyValuesHolder保存属性名称,拥有set方法(用于反射),通过Keyframes使用估值器计算值。
PropertyValuesHolder.java
String mPropertyName;// 属性名称 例如translationX、scaleX、alpha等
Method mSetter = null; // 属性的set方法
private TypeEvaluator mEvaluator; // 估值器
Keyframes mKeyframes = null; // 计算时间和数值关系的,给定时间,返回动画值的。使用估值器计算。
void calculateValue(float fraction) {
// 根据进度使用估值器计算具体值
Object value = mKeyframes.getValue(fraction);
mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
}
Keyframe
Keyframe关键帧:
-
fraction:表示当前的属性值变化百分比;
-
value:表示当前应该在的位置
KeyframeSet:关键帧集合。
public class KeyframeSet implements Keyframes
public static KeyframeSet ofFloat(float... values) {
boolean badValue = false;
int numKeyframes = values.length;
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
if (numKeyframes == 1) {
// 一个具体值,默认 keyframes[0]为0
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
if (Float.isNaN(values[0])) {
badValue = true;
}
} else {
// 多个具体值
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
for (int i = 1; i < numKeyframes; ++i) {
// 关键帧的Keyframe.fraction(属性值变化百分比)是等分的。
keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
if (Float.isNaN(values[i]))
{
badValue = true;
}
}
}
if (badValue) {
Log.w("Animator", "Bad value (NaN) in float animator");
}
return new FloatKeyframeSet(keyframes);
}
以FloatKeyframeSet为例。
class FloatKeyframeSet extends KeyframeSet implements Keyframes.FloatKeyframes {
@Override public float getFloatValue(float fraction) {
if (fraction <= 0f) { ..... return xxxx }
else if (fraction >= 1f) { ....... return xxxx }
// fraction 在(0, 1)
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
for (int i = 1; i < mNumKeyframes; ++i) {
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
// 找到fraction 所在 [prevKeyframe, nextKeyframe]
if (fraction < nextKeyframe.getFraction()) {
final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
// 把fraction换算到 [preKeyframe, nextKeyframe] 间变化率
// 后续例子,比如:fraction=0.2,应该在[0.1,0.2]关键帧之间, (0.2 - 0)/ (0.25 - 0) = 0.8
// intervalFraction = 0.8,就是在[0.1, 0.2]关键帧区间的属性值变化率
float intervalFraction = (fraction - prevKeyframe.getFraction()) / (nextKeyframe.getFraction() - prevKeyframe.getFraction());
float prevValue = prevKeyframe.getFloatValue();
float nextValue = nextKeyframe.getFloatValue();
// Apply interpolator on the proportional duration.
if (interpolator != null) {
intervalFraction = interpolator.getInterpolation(intervalFraction);
}
return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). floatValue();
}
prevKeyframe = nextKeyframe;
}
// shouldn't get here
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
}
Keyframe就是动画初始化时设置的属性值,每设置一个值,表示一个Keyframes对象。每个动画至少2个Keyframe(表示开始和结束)。
动画设置多个值(也能控制属性变化率的),就有多个关键帧。
如下例子,每个关键帧都等分属性变化比。设置了5个值,会把动画属性变化比等分4份,每份1/4,0.1是起始值,属性变化比[0,0.25] 在值[0.1, 0.2]之间变化;属性变化比[0.25,0.5] 在值[0.2,0.3]之间变化。
ObjectAnimator.ofFloat(mImage1, "scaleY", 0.1, 0.2, 0.3, 0.5, 1)
自己设置关键帧的参数。
Keyframe keyframe1 = Keyframe.ofFloat(0,0);
Keyframe keyframe2 = Keyframe.ofFloat(0.2f,200);
Keyframe keyframe3 = Keyframe.ofFloat(0.7f,100);
Keyframe keyframe4 = Keyframe.ofFloat(1,300);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3,keyframe4);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(imageView,holder);