本文基于Android 12进行学习研究,参考《深入理解Android内核源码》思路学习总结,如有理解不对,望各位朋友指正,另外可能留存一些疑问,留后续再探索。输出只是为了分享和提升自己。
动画初始化
按照窗口管理策略类中的定义,动画应该被分为四种类型。
-
TRANSIT_ENTER
:窗口进入。
-
TRANSIT_EXIT
:窗口移除。
-
TRANSIT_SHOW
:窗口可见。
-
TRANSIT_HIDE
:窗口隐藏。
而
TRANSIT_PREVIEW_DONE
其实不算是动画,而是一个标志启动窗口完成的标志位。在
WMS
的
relayoutWindow
函数,会根据窗口状态判断是否要执行动画。下面代码则是判断动画的起始点。
//仅有在窗口在可见状态下且是一个启动窗口类型或者关联的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
函数执行动画。
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
函数。
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进行属性计算的地方。
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
执行动画。
// 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。
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
函数。
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
函数。
private void startAnimations(long frameTimeNanos) {
synchronized (mLock) {
startPendingAnimationsLocked();
}
mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);
}
遍历
mPendingAnimations
中所有等待帧信号来临的
RunningAnimation
对象,调用
startAnimationLocked
执行它们。
private void startPendingAnimationsLocked() {
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
startAnimationLocked(mPendingAnimations.valueAt(i));
}
mPendingAnimations.clear();
}
SurfaceAnimatorRunner
对象,
startAnimationLocked
主要为每个
RunningAnimation
动画创建
ValueAnimator
对象并设置相关参数,并在
AnimatorUpdateListener
回调中计算动画应用对象的相关属性。
@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
注册帧信号的监听。
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
也为我们提供 设置类似编舞者提供周期信号的 接口,方便测试和特定功能开发。
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
移除。
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
函数。
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
函数计算此时此刻动画的相关属性值。参数为帧时间(开始之后)或者开始时间(刚开始)。
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,则表示是新的循环。
这个函数有很多设计妙处。
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
函数。
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
设置监听的地方。
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
函数。
private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
}
apply
函数获取线程本地
TmpValues
对象,将相关属性计算结果写到其
Transformation
类型的
transformation
成员变量。
Transformation
类封装
Matrix
、裁剪、透明度、动画类型。而
Matrix
可以对对象进行缩放、平移、和旋转。也就是说,
Transformation
类型囊括了四个动画类型缩放、平移、旋转、透明度,代表了动画某刻要应用的变换。
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
函数。
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
为准,如前面由系统默认指定的动画。
public void getTransformationAt(float normalizedTime, Transformation outTransformation) {
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
applyTransformation(interpolatedTime, outTransformation);
}
动画的展示
回到了
SurfaceAnimatorRunner
对像
startAnimationLocked
函数给
ValueAnimator
设置监听的地方。在上面执行了applyTransformation函数之后,调用了applyTransformation。
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来计算动画的各个属性 ,因此进一步确定原理,动画就是在指定的时间内播放一帧帧图像,根据人眼对图像的感知特色,从而形成动效。
另外,动画会以垂直信号来初始化动画和触发动画的开始。
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓
(文末还有ChatGPT机器人小福利哦,大家千万不要错过)
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题