首先说说动画的运行模式,一共有两种模式:
接下来我们看看动画的运行原理,一般情况下我们会调用使用如下的方式开启动画:
AlphaAnimation animation = new AlphaAnimation(0,1f);
animation.setDuration(200);
animation.setFillAfter(true);
button.startAnimation(animation);
重点在startAnimation这个方法,这个方法是在哪定义的呢?是在所有控件的父类,View中,所以我们去View的源码中看看。
public void startAnimation(Animation animation) {
animation.setStartTime(Animation.START_ON_FIRST_FRAME);
setAnimation(animation);
invalidateParentCaches();
invalidate(true);
}
首先给animation设置了一个起始时间START_ON_FIRST_FRAME,这个值是Animation类中定义的一个常量,值为-1,然后调用View中的setAnimation传入我们的动画对象,
public void setAnimation(Animation animation) {
mCurrentAnimation = animation;
if (animation != null) {
// If the screen is off assume the animation start time is now instead of // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time // would cause the animation to start when the screen turns back on if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());
}
animation.reset();
}
}
在setAnimation方法里面,我们的animation对象会赋值给mCurrentAnimation这样一个全局变量,然后进行了判断,满足条件的话又重新设置了动画的时间,
public static long currentAnimationTimeMillis() {
return SystemClock.uptimeMillis();
}
这里返回了一个系统时间。然后调用reset方法重置动画为初始状态。
也就是说setAnimation主要做了两件事。第一件事就是设置动画起始时间,第二件事是重置动画状态。
最后调用invalidata方法重绘自己。
既然调用了setAnimation设置动画,那么应该有getAnimation来获取动画吧,最后我们在View的draw(Canvas canvas, ViewGroup parent, long drawingTime)里面发现了getAnimation这个方法。
Transformation transformToApply = null;
boolean concatMatrix = false;
final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired;
final Animation a = getAnimation();
if (a != null) {
more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
concatMatrix = a.willChangeTransformationMatrix();
if (concatMatrix) {
mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
}
transformToApply = parent.getChildTransformation();
public Animation getAnimation() {
return mCurrentAnimation;
}
这个getAnimation方法返回的正是我们定义的动画对象,因为我们之前在setAniamation方法中,将动画对象赋值给了这个全局变量。
接下来有调用了applyLegacyAnimation这个方法,
private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
Animation a, boolean scalingRequired) {
Transformation invalidationTransform;
final int flags = parent.mGroupFlags;
final boolean initialized = a.isInitialized();
if (!initialized) {
a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
onAnimationStart();
}
final Transformation t = parent.getChildTransformation();
boolean more = a.getTransformation(drawingTime, t, 1f);
if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
if (parent.mInvalidationTransformation == null) {
parent.mInvalidationTransformation = new Transformation();
}
invalidationTransform = parent.mInvalidationTransformation;
a.getTransformation(drawingTime, invalidationTransform, 1f);
} else {
invalidationTransform = t;
}
我们只看重点代码,这里调用了动画对象的getTransformation方法
public boolean getTransformation(long currentTime, Transformation outTransformation,
float scale) {
mScaleFactor = scale;
return getTransformation(currentTime, outTransformation);
}
该方法直接调用了两个参数的方法
public boolean getTransformation(long currentTime, Transformation outTransformation) {
if (mStartTime == -1) {
mStartTime = currentTime;
}
final long startOffset = getStartOffset();
final long duration = mDuration;
float normalizedTime;
if (duration != 0) {
normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
(float) duration;
} else {
// time is a step-change with a zero duration
normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
}
final boolean expired = normalizedTime >= 1.0f;
mMore = !expired;
if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
if (!mStarted) {
fireAnimationStart();
mStarted = true;
if (USE_CLOSEGUARD) {
guard.open("cancel or detach or getTransformation");
}
}
if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if (mCycleFlip) {
normalizedTime = 1.0f - normalizedTime;
}
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
}
该方法首先将当前时间currentTime处理成一个float类型的代表当前动画进度的对象。
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
然后将我们计算好的时间传入getInterpolation方法里面,获得一个插值器对应的时间,最后把这个时间和Transformation对象传入到applyTransformation方法中。
protected void applyTransformation(float interpolatedTime, Transformation t) {
}
我们发现applyTransformation这个方法的实现是空的,为何呢?因为不同的子类对这个方法进行了不同的实现。接下来我们看看
AlphaAnimation
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float alpha = mFromAlpha;
t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
}
ScaleAnimation
protected void applyTransformation(float interpolatedTime, Transformation t) {
float sx = 1.0f;
float sy = 1.0f;
float scale = getScaleFactor();
if (mFromX != 1.0f || mToX != 1.0f) {
sx = mFromX + ((mToX - mFromX) * interpolatedTime);
}
if (mFromY != 1.0f || mToY != 1.0f) {
sy = mFromY + ((mToY - mFromY) * interpolatedTime);
}
if (mPivotX == 0 && mPivotY == 0) {
t.getMatrix().setScale(sx, sy);
} else {
t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
}
}
RotateAnimation
protected void applyTransformation(float interpolatedTime, Transformation t) {
float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) * interpolatedTime);
float scale = getScaleFactor();
if (mPivotX == 0.0f && mPivotY == 0.0f) {
t.getMatrix().setRotate(degrees);
} else {
t.getMatrix().setRotate(degrees, mPivotX * scale, mPivotY * scale);
}
}
TranslateAnimation
protected void applyTransformation(float interpolatedTime, Transformation t) {
float dx = mFromXDelta;
float dy = mFromYDelta;
if (mFromXDelta != mToXDelta) {
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
}
if (mFromYDelta != mToYDelta) {
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
}
t.getMatrix().setTranslate(dx, dy);
}
可见applyTransformation()方法就是动画具体的实现,系统会以一个比较高的频率来调用这个方法,一般情况下60FPS,是一个非常流畅的画面了,也就是16ms,接下来我们验证一下这个时间。
public void click(View vIew){
Animation animation = new Animation() {
private long last = 0;
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
long curr = System.currentTimeMillis();
long time = curr-last;
last = curr;
System.out.println("===time: "+time);
t.getMatrix().postTranslate(10, 10);
}
};
animation.setDuration(500);
textView.startAnimation(animation);
}
可以看到时间间隔大概在20ms左右