本文基于Android 12进行学习研究,参考《深入理解Android内核源码》思路学习总结,如有理解不对,望各位朋友指正,另外可能留存一些疑问,留后续再探索。输出只是为了分享和提升自己。
动画初始化
按照窗口管理策略类中的定义,动画应该被分为四种类型。
TRANSIT_ENTER
:窗口进入。TRANSIT_EXIT
:窗口移除。TRANSIT_SHOW
:窗口可见。TRANSIT_HIDE
:窗口隐藏。
而TRANSIT_PREVIEW_DONE
其实不算是动画,而是一个标志启动窗口完成的标志位。在WMS
的relayoutWindow
函数,会根据窗口状态判断是否要执行动画。下面代码则是判断动画的起始点。
java
//仅有在窗口在可见状态下且是一个启动窗口类型或者关联的appToken不隐藏时才会进行重新布局
final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
(win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
|| win.mActivityRecord.isClientVisible());
//当前不需要重新布局、也已经有Surface,且不是在执行退出动画,则需要考虑是否执行动画
if (!shouldRelayout && winAnimator.hasSurface() && !win.mAnimatingExit) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
if (!win.mWillReplaceWindow) {
......
//尝试开始或者退出动画
focusMayChange = tryStartExitingAnimation(win, winAnimator, focusMayChange);
}
}
在tryStartExitingAnimation
调用了WindowStateAnimator
类型对象winAnimator
的applyAnimationLocked
函数执行动画。
java
private boolean tryStartExitingAnimation(WindowState win, WindowStateAnimator winAnimator,boolean focusMayChange) {
int transit = WindowManagerPolicy.TRANSIT_EXIT;
//属性类型是应用窗口
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
//启动窗口完成
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
//窗口处于动画变换
if (win.inTransition()) {
focusMayChange = true;
win.mAnimatingExit = true;
} else if (win.isWinVisibleLw() && win.mDisplayContent.okToAnimate()) {
String reason = null;
//执行动画,如果未执行动画或动画失败,则释放相关资源
if (winAnimator.applyAnimationLocked(transit, false)) {
reason = "applyAnimation";
focusMayChange = true;
win.mAnimatingExit = true;
} else if (
win.isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION)
|| win.isAnimating(PARENTS | TRANSITION,ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)|| (win.inTransition()
reason = "animating";
win.mAnimatingExit = true;
} else if (win.mDisplayContent.mWallpaperController.isWallpaperTarget(win)
&& win.mAttrs.type != TYPE_NOTIFICATION_SHADE) {
reason = "isWallpaperTarget";
win.mAnimatingExit = true;
}
.....
}
}
//资源释放
if (!win.mAnimatingExit) {
boolean stopped = win.mActivityRecord == null || win.mActivityRecord.mAppStopped;
win.mDestroying = true;
win.destroySurface(false, stopped);
}
if (mAccessibilityController.hasCallbacks()) {
mAccessibilityController.onWindowTransition(win, transit);
}
return focusMayChange;
}
applyAnimationLocked
函数选择合适的动画类型,并设置给WindowState
,这里也是 判断是否有设置动画的地方。如果设置了动画,调用WindowState
的startAnimation
函数。
java
boolean applyAnimationLocked(int transit, boolean isEntrance) {
//避免加载相同动画两次
if (mWin.isAnimating() && mAnimationIsEntrance == isEntrance) {
return true;
}
if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
mWin.getDisplayContent().adjustForImeIfNeeded();
if (isEntrance) {
mWin.setDisplayLayoutNeeded();
mService.mWindowPlacerLocked.requestTraversal();
}
}
if (mWin.mControllableInsetProvider != null) {
// All our animations should be driven by the insets control target.
return false;
}
// 如果显示处于 frozen状态,则不执行动画
if (mWin.mToken.okToAnimate()) {
int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimation(mWin, transit);
int attr = -1;
Animation a = null;
//anim不等于ANIMATION_STYLEABLE,表示给窗口指定了动画
if (anim != DisplayPolicy.ANIMATION_STYLEABLE) {//anim不等于0,表示指定了动画
if (anim != DisplayPolicy.ANIMATION_NONE) {
//加载动画资源
a = AnimationUtils.loadAnimation(mContext, anim);
}
} else {
//根据动画类型,选择默认的资源文件
switch (transit) {
case WindowManagerPolicy.TRANSIT_ENTER:
attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
break;
case WindowManagerPolicy.TRANSIT_EXIT:
attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
break;
case WindowManagerPolicy.TRANSIT_SHOW:
attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
break;
case WindowManagerPolicy.TRANSIT_HIDE:
attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
break;
}
//加载动画资源
if (attr >= 0) {
a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
mWin.mAttrs, attr, TRANSIT_OLD_NONE);
}
}
if (a != null) {
mWin.startAnimation(a);//获取到动画资源,开始执行动画Animation对象
mAnimationIsEntrance = isEntrance;
}
} else {
mWin.cancelAnimation();
}
return mWin.isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
}
WindowState
在WMS表示一个窗口对象,startAnimation
函数对动画anim进行进行初始化,封装成AnimationAdpater
类型的adapter
对象,并调用父类WindowContainer
的startAnimation
函数。WindowContainer
定义了窗口和窗口层级之间一些通用接口。WindowContainer
用来描述动画和联系相关联的组件,以及执行动画的。
注意到这里adpter
实际类型是LocalAnimationAdapter
,表示该动画不需要持有WindowManager
锁。重点是其构造函数的入参WindowAnimationSpec
和SurfaceAnimationRunner
对象,是后续监听VSYNC进行属性计算的地方。
java
void startAnimation(Animation anim) {
if (mControllableInsetProvider != null) {
return;
}
final DisplayInfo displayInfo = getDisplayInfo();
//初始化宽高
anim.initialize(mWindowFrames.mFrame.width(), mWindowFrames.mFrame.height(),
displayInfo.appWidth, displayInfo.appHeight);
anim.restrictDuration(MAX_ANIMATION_DURATION);
anim.scaleCurrentDuration(mWmService.getWindowAnimationScaleLocked());
//SurfaceAnimationRunner类型的 mWmService.mSurfaceAnimationRunner
final AnimationAdapter adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(anim, mSurfacePosition, false,
0),
mWmService.mSurfaceAnimationRunner);
//getPendingTransaction分析
startAnimation(getPengetPendingTransaction分析dingTransaction(), adapter);
commitPendingTransaction();
}
WindowContainer.startAnimation
函数又调用了SurfaceAnimator.startAnimation
。SurfaceAnimator
主要是将一组子Surface
通过约束重置为新的Surface
,称为Leach
,然后交由AnimationAdapter
执行动画。
java
// mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION
//animationFinishedCallback、animationCancelledCallback、snapshotAnim此时为null
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
@Nullable Runnable animationCancelledCallback,
@Nullable AnimationAdapter snapshotAnim) {
mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
animationCancelledCallback, snapshotAnim, mSurfaceFreezer);
}
startAnimation
建立动画链成功之后,就会调用入参anim
执行动画。hidden
表示WindowContainer
当前持有Surface
是否可见。按前面分析,此时startAnimation
只有前面四个参数有值。三种动画:Surface、adapter、snapshot。
java
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
@AnimationType int type,
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
@Nullable Runnable animationCancelledCallback,
@Nullable AnimationAdapter snapshotAnim, @Nullable SurfaceFreezer freezer) {
//强制取消与t相同类型的动画,并重新执行
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mAnimation = anim;
mAnimationType = type;
mSurfaceAnimationFinishedCallback = animationFinishedCallback;
mAnimationCancelledCallback = animationCancelledCallback;
final SurfaceControl surface = mAnimatable.getSurfaceControl();
if (surface == null) {
cancelAnimation();
return;
}
//freezer==null
mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
if (mLeash == null) {
//创建动画链(SurfaceController),同时也会设置给t
mLeash = createAnimationLeash(mAnimatable, surface, t, type,
mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
0 /* y */, hidden, mService.mTransactionFactory);
mAnimatable.onAnimationLeashCreated(t, mLeash);
}
//开始动画链
mAnimatable.onLeashAnimationStarting(t, mLeash);
if (mAnimationStartDelayed) {
return;
}
//此时执行AnimationAdapter对象mAnimation动画,mInnerAnimationFinishedCallback是WC的监听
mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
//开始snapshot动画,此时snapshotAnim==null
if (snapshotAnim != null) {
mSnapshot = freezer.takeSnapshotForAnimation();
if (mSnapshot == null) {
return;
}
mSnapshot.startAnimation(t, snapshotAnim, type);
}
}
按前面的分析,这里mAnimation
的实际类型是LocalAnimationAdapter
。其startAnimation
又调用了SurfaceAnimationRunner
对象的startAnimation
函数。
先是将动画相关内容封装成RunningAnimation
对象,并存放到mPendingAnimations
中。
然后向编舞者Choreographer
注册了VSYNC
监听,这样当信号来临时,会调用startAnimations
函数。
java
void startAnimation(AnimationSpec a, SurfaceControl animationLeash, Transaction t,
Runnable finishCallback) {
synchronized (mLock) {
final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
finishCallback);
//这样帧信号来临时,会执行该Map中所有动画
mPendingAnimations.put(animationLeash, runningAnim);
//如果当前动画部延迟执行,则立即向Choreographer注册垂直信号监听
//这样垂直信号来临时,执行startAnimations,存在一定延迟
if (!mAnimationStartDeferred) {
mChoreographer.postFrameCallback(this::startAnimations);
}
//一些动画需要初始并应用一些变换
applyTransformation(runningAnim, t, 0 /* currentPlayTime */);
}
}
SurfaceAnimationRunner
的startAnimations
函数。
java
private void startAnimations(long frameTimeNanos) {
synchronized (mLock) {
startPendingAnimationsLocked();
}
mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);
}
遍历mPendingAnimations
中所有等待帧信号来临的RunningAnimation
对象,调用startAnimationLocked
执行它们。
java
private void startPendingAnimationsLocked() {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
startAnimationLocked(mPendingAnimations.valueAt(i));
}
mPendingAnimations.clear();
}
SurfaceAnimatorRunner
对象,startAnimationLocked
主要为每个RunningAnimation
动画创建ValueAnimator
对象并设置相关参数,并在AnimatorUpdateListener
回调中计算动画应用对象的相关属性。
java
@GuardedBy("mLock")
private void startAnimationLocked(RunningAnimation a) {
final ValueAnimator anim = mAnimatorFactory.makeAnimator();
//设置动画相关参数
anim.overrideDurationScale(1.0f);
anim.setDuration(a.mAnimSpec.getDuration());
//更改动画对象相关属性
anim.addUpdateListener(animation -> {
synchronized (mCancelLock) {
if (!a.mCancelled) {
final long duration = anim.getDuration();
long currentPlayTime = anim.getCurrentPlayTime();
if (currentPlayTime > duration) {
currentPlayTime = duration;
}
//每次更改相关动画属性
applyTransformation(a, mFrameTransaction, currentPlayTime);
}
}
scheduleApplyTransaction();
});
//anim开始后,会回调此处。
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
synchronized (mCancelLock) {
if (!a.mCancelled) {
mFrameTransaction.setAlpha(a.mLeash, 1);
}
}
}
@Override
public void onAnimationEnd(Animator animation) {
synchronized (mLock) {
mRunningAnimations.remove(a.mLeash);
synchronized (mCancelLock) {
if (!a.mCancelled) {
mAnimationThreadHandler.post(a.mFinishCallback);
}
}
}
}
});
a.mAnim = anim;
mRunningAnimations.put(a.mLeash, a);
//调用ValueAnimator的start函数。
anim.start();
if (a.mAnimSpec.canSkipFirstFrame()) {
anim.setCurrentPlayTime(mChoreographer.getFrameIntervalNanos() / NANOS_PER_MS);
}
//手动触发一帧动画属性
anim.doAnimationFrame(mChoreographer.getFrameTime());
}
ValueAnimator.start=>start(false),
该函数主要ValueAnimator
对象对一些变量进行初始化。其中调用了addAnimationCallback(0)
向AnimationHandler
注册帧信号的监听。
java
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
mReversing = playBackwards;//此时false,表示为正向动画
mSelfPulse = !mSuppressSelfPulseRequested;
//判断是否快进到某个时间点
if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
if (mRepeatCount == INFINITE) {
// Calculate the fraction of the current iteration.
float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
mSeekFraction = 1 - fraction;
} else {
mSeekFraction = 1 + mRepeatCount - mSeekFraction;
}
}
mStarted = true;
mPaused = false;
mRunning = false;
mAnimationEndRequested = false;
mLastFrameTime = -1;
mFirstFrameTime = -1;
mStartTime = -1;
addAnimationCallback(0);
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
//内部初始化动画对象所应用的属性,和回调开始监听
startAnimation();
//初始化mStartTime
if (mSeekFraction == -1) {
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
AnimationHandler
在线程中静态单例的,在默认情况下,向编舞者Choreographer
注册并接收其帧信号(垂直信号)回调, 向所有的动画ValueAnimator
对象发送刷新帧的时间,这样它们在同一个线程以相同的时间执行各自窗口属性值的计算,达到视觉动画效果。AnimationHandler
也为我们提供 设置类似编舞者提供周期信号的 接口,方便测试和特定功能开发。
java
private void addAnimationCallback(long delay) {
if (!mSelfPulse) {
return;
}
getAnimationHandler().addAnimationFrameCallback(this, delay);
}
public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
//注册垂直信号监听
if (mAnimationCallbacks.size() == 0) {
getProvider().postFrameCallback(mFrameCallback);
}
//避免重复添加
if (!mAnimationCallbacks.contains(callback)) {
mAnimationCallbacks.add(callback);
}
//延时执行
if (delay > 0) {
mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
}
}
//这样垂直信号来临,会调用doFrame函数
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
动画触发
AnimationHandler
默认情况会向编舞者Choreographer
注册垂直信号(VSYNC
)监听,这样当垂直信号来临时,就回调mFrameCallback
对象doFrame
函数。
doFrame
函数获取当前帧时间并传递给doAnimationFrame
函数,如果执行完之后,还有动画没有执行完成则再次监听VSYNC。所以在doAnimationFrame
函数中执行动画结束后肯定将AnimationFrameCallback
对象从mAnimationCallbacks
移除。
java
private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
doAnimationFrame(getProvider().getFrameTime());
if (mAnimationCallbacks.size() > 0) {
getProvider().postFrameCallback(this);
}
}
};
doAnimationFrame
函数遍历mAnimationCallbacks
中所有AnimationFrameCallback
对象,判断其是否达到开始执行动画(部分动画可能设置延时执行),到达开始时间,则调用它们的doAnimationFrame
函数。
java
private void doAnimationFrame(long frameTime) {
long currentTime = SystemClock.uptimeMillis();
final int size = mAnimationCallbacks.size();
for (int i = 0; i < size; i++) {
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
//判断动画是否达到开始执行时间
if (isCallbackDue(callback, currentTime)) {
callback.doAnimationFrame(frameTime);//回调AnimationFrameCallback,进行逻辑处理
if (mCommitCallbacks.contains(callback)) {//查看在哪里注册到该map,延迟大的时候
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
//延时问题
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
cleanUpList();
}
ValueAnimator
对象doAnimationFrame
函数。在VSYNC
来临时,需要根据一些情况调整动画的开始时间mStartTime
。动画未开始、恢复动画、暂停动画、动画快进、动画延迟执行都会调整动画的开始时间。如果此时动画未开始,此帧时间则是开始时间,或者开始倒计时的时间(动画设置延时执行)。如果当前是恢复动画,开始时间则更改为当前时间节点+已暂停时间(mStartTime+elapseTime),而不是停留在上次动画的帧时间。这里可能会理解为从继续上次暂停的动画效果,然后继续执行后续动画。如果此时还是第一帧时间,还需要判断是否存在动画快进的情况。
最后调用animateBasedOnTime
函数计算此时此刻动画的相关属性值。参数为帧时间(开始之后)或者开始时间(刚开始)。
java
public final boolean doAnimationFrame(long frameTime) {
//动画刚初始化,mStartTime=-1,未开始
if (mStartTime < 0) {
// 第一帧动画时间,如果有延迟开始动画,此时开始倒计时
mStartTime = mReversing
? frameTime
: frameTime + (long) (mStartDelay * resolveDurationScale());
}
if (mPaused) {//暂停
mPauseTime = frameTime;
removeAnimationCallback();
return false;
} else if (mResumed) {//恢复
mResumed = false;
if (mPauseTime > 0) {
//恢复并不是从上次动画进度节点恢复,而是以当前帧时间为开始
mStartTime += (frameTime - mPauseTime);
}
}
if (!mRunning) {
//动画开始时间未到,并且没有快进
if (mStartTime > frameTime && mSeekFraction == -1) {
return false;
} else {
mRunning = true;
//初始化ValueAnimator中各个属性值
startAnimation();
}
}
if (mLastFrameTime < 0) {//此次第一帧时间
if (mSeekFraction >= 0) {
long seekTime = (long) (getScaledDuration() * mSeekFraction);
mStartTime = frameTime - seekTime;
mSeekFraction = -1;
}
mStartTimeCommitted = false; // allow start time to be compensated for jank
}
mLastFrameTime = frameTime;
//避免当前帧时间比开始时间早的问题
final long currentTime = Math.max(frameTime, mStartTime);
//计算属性值
boolean finished = animateBasedOnTime(currentTime);
if (finished) {
endAnimation();//移除FrameCallback监听,通知已注册监听
}
return finished;
}
我们知道动画是可以指定重复次数或无限循环的。所以animateBasedOnTime
函数计算出本次帧时间来临时,本次动画进度在整体进度情况fraction
。0表示刚开始执行动画;0-1表示第一次动画某个时间点;等于1表示刚好执行完第一次动画;大于1则表示开始循环动画。当大于1时,正数部分表示第几次重复动画,而小数部分表示本次动画的时间节点;正数部分如果大于上次fraction,则表示是新的循环。
这个函数有很多设计妙处。
java
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
//获取持续时间
final long scaledDuration = getScaledDuration();
//currentTime - mStartTime表示动画已执行完的时间长度,等于0表示刚开始,大于0,说明要跳过这部分时间。
//(float)(currentTime - mStartTime) / scaledDuration大于1表示已经开始重复执行动画了,0-1则是第一次。1刚好第一次动画结束
final float fraction = scaledDuration > 0 ?
(float)(currentTime - mStartTime) / scaledDuration : 1f;
final float lastFraction = mOverallFraction;
//fraction在整型比上一次大,则判断为新一次循环,相等判断为同一次动画内的不同阶段
final boolean newIteration = (int) fraction > (int) lastFraction;
//判断是否最后一次动画循环:在有限循环次数内,本次动画等于或超出设置的总重复次数
final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
(mRepeatCount != INFINITE);
if (scaledDuration == 0) {
//持续时间为0的,直接结束
done = true;
} else if (newIteration && !lastIterationFinished) {
// 当前属于新的迭代次数,且还没有结束动画
if (mListeners != null) {
int numListeners = mListeners.size();
for (int i = 0; i < numListeners; ++i) {
mListeners.get(i).onAnimationRepeat(this);
}
}
} else if (lastIterationFinished) {
done = true;//当前属于最后一次迭代
}
mOverallFraction = clampFraction(fraction);//缓存本次进度节点
//先计算本次动画是第几次iteration
//再取小数部分curFraction=fraction-iteration,根据是否反向动画,确定最终的进度curFraction or 1-curFraction
float currentIterationFraction = getCurrentIterationFraction(
mOverallFraction, mReversing);
animateValue(currentIterationFraction);//通过插值器计算动画属性值
}
return done;
}
animateValue
函数以本次动画时间进度节点,通过时间插值器变换进度节点,然后通知属性数组mValues
中的对象,让它们根据变换后fraction
,转化具体的属性值。然后回调UpdateListener
对象的onAnimationUpdate
函数。
java
void animateValue(float fraction) {
//插值器变换fraction
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
//各个属性根据fraction转化自己的值
mValues[i].calculateValue(fraction);
}
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
//回调通知
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
这就回到了SurfaceAnimatorRunner
对像startAnimationLocked
函数给ValueAnimator
设置监听的地方。
java
private void startAnimationLocked(RunningAnimation a) {
......
//帧动画通过valueAnimator计算产生后回调此处
anim.addUpdateListener(animation -> {
synchronized (mCancelLock) {
if (!a.mCancelled) {
final long duration = anim.getDuration();
long currentPlayTime = anim.getCurrentPlayTime();
if (currentPlayTime > duration) {//执行结束
currentPlayTime = duration;
}
//动画属性计算
applyTransformation(a, mFrameTransaction, currentPlayTime);
}
}
// Transaction will be applied in the commit phase.
scheduleApplyTransaction();
});
......
}
applyTransformation
函数内部有调用了WindowAnimationSpec
对象的apply
函数。
arduino
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}
apply
函数获取线程本地TmpValues
对象,将相关属性计算结果写到其Transformation
类型的transformation
成员变量。Transformation
类封装Matrix
、裁剪、透明度、动画类型。而Matrix
可以对对象进行缩放、平移、和旋转。也就是说,Transformation
类型囊括了四个动画类型缩放、平移、旋转、透明度,代表了动画某刻要应用的变换。
ini
public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
final TmpValues tmp = mThreadLocalTmps.get();
//重置transformation
tmp.transformation.clear();
//计算某个时刻的动画属性,并将结果写会tmp.transformation
mAnimation.getTransformation(currentPlayTime, tmp.transformation);
//位移
tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
//旋转、缩放
t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
//透明度
t.setAlpha(leash, tmp.transformation.getAlpha());
boolean cropSet = false;
if (mRootTaskClipMode == ROOT_TASK_CLIP_NONE) {
if (tmp.transformation.hasClipRect()) {
t.setWindowCrop(leash, tmp.transformation.getClipRect());
cropSet = true;
}
} else {
mTmpRect.set(mRootTaskBounds);
if (tmp.transformation.hasClipRect()) {
mTmpRect.intersect(tmp.transformation.getClipRect());
}
t.setWindowCrop(leash, mTmpRect);
cropSet = true;
}
//设置圆角
if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
t.setCornerRadius(leash, mWindowCornerRadius);
}
}
代码中调用了Animation
的getTransformation
函数,主要是计算动画的状态,是否开始、运行、结束。如果动画还是处于运行状态,则调用getTransformationAt
函数。
java
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) {
//计算当前所处的位置0
normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
(float) duration;
} else {
//未开始或者结束了
normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
}
//动画结束了,或者被取消。
final boolean expired = normalizedTime >= 1.0f || isCanceled();
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 (NoImagePreloadHolder.USE_CLOSEGUARD) {
guard.open("cancel or detach or getTransformation");
}
}
//normalized在0f~1f之间
if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
//此时是否反向动画
if (mCycleFlip) {
normalizedTime = 1.0f - normalizedTime;
}
//将动画属性缓冲到outTransformation
getTransformationAt(normalizedTime, outTransformation);
}
//结束了,但是可能循环动画
if (expired) {
if (mRepeatCount == mRepeated || isCanceled()) {//动画结束
if (!mEnded) {
mEnded = true;
guard.close();
fireAnimationEnd();
}
} else {//动画循环
if (mRepeatCount > 0) {
mRepeated++;
}
if (mRepeatMode == REVERSE) {
mCycleFlip = !mCycleFlip;
}
mStartTime = -1;
mMore = true;
fireAnimationRepeat();
}
}
if (!mMore && mOneMoreTime) {
mOneMoreTime = false;
return true;
}
return mMore;
}
getTransformationAt
函数内部又调用Animation
的applyTransformation
函数。这里的Animation
子类会重写该函数,实现自己的特定属性计算。Animation
子类可以是在主题或者指定的Animation
为准,如前面由系统默认指定的动画。
java
public void getTransformationAt(float normalizedTime, Transformation outTransformation) {
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
}
动画的展示
回到了SurfaceAnimatorRunner
对像startAnimationLocked
函数给ValueAnimator
设置监听的地方。在上面执行了applyTransformation函数之后,调用了applyTransformation。
java
private final Runnable mApplyTransactionRunnable = this::applyTransaction;
private void scheduleApplyTransaction() {
if (!mApplyScheduled) {
mChoreographer.postCallback(CALLBACK_TRAVERSAL, mApplyTransactionRunnable,
null /* token */);
mApplyScheduled = true;
}
}
private void applyTransaction() {
mFrameTransaction.setAnimationTransaction();
mFrameTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
mFrameTransaction.apply();
mApplyScheduled = false;
}
根据前面mSurfaceAnimationRunner对象来自WMS的成员变量,其在WMS创建的时候被创建,Transaction类型的mFrameTransaction对象以同步方式设置SurfaceController。applyTransaction函数调用mFrameTransaction对象的几个方法,内部都调用底层代码去设置Surface。这里不再进一步跟进。
总结
通过本文对动画源码的学习,了解在动画上面对Float浮点数巧妙运用,用来合理控制动画的重复行为和单次进度。
同时也了解到动画在底层也是通过ValueAnimator来计算动画的各个属性 ,因此进一步确定原理,动画就是在指定的时间内播放一帧帧图像,根据人眼对图像的感知特色,从而形成动效。
另外,动画会以垂直信号来初始化动画和触发动画的开始。