背景
为了实现Fragment的切换动画,不得不对Fragment的添加过程有个基本了解。关于Fragment transition动画可以参考Activity和Fragment Transition介绍。
Android原生提供了三种fragment的transition效果,Explode,Fade,Slide。要实现自己的transition动画效果可以继承这三个类,重写对应onAppear/onDisappear方法可快速实现。当然也可以直接继承他们的父类android.transition.Visibility,丰俭由人。
结合replace Fragment操作以及onAppear/onDisappear方法的调用尝试探索下Fragment transition背后的实现原理。
从fragment的替换开始
getFragmentManager().beginTransaction().replace(contentId, fragment).commit();
1)getFragmentManager()->FragmentController.getFragmentManager()->FragmentHostCallback.getFragmentManagerImpl()沿着调用链跟进,获取到FragmentManagerImpl实例。
2)跟进FragmentManagerImpl.beginTransaction(),获取到BackStackRecord实例
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
3)BackStackRecord中replace最主要的操作
void addOp(Op op) {
mOps.add(op);
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim = mPopExitAnim;
}
4)继续BackStackRecord.commit操作
int commitInternal(boolean allowStateLoss) {
if (mCommitted) {
throw new IllegalStateException("commit already called");
}
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new FastPrintWriter(logw, false, 1024);
dump(" ", null, pw, null);
pw.flush();
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
这个mManager是上面的FragmentManagerImpl,继续跟进
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
if (allowStateLoss) {
// This FragmentManager isn't attached, so drop the entire transaction.
return;
}
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}
继续到scheduleCommit
private void scheduleCommit() {
synchronized (this) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
mExecCommit是一个Runnable,调用了execPendingActions方法
/**
* Only call from main thread!
*/
public boolean execPendingActions() {
ensureExecReady(true);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
doPendingDeferredStart();
burpActive();
return didSomething;
}
后续经过一系列调用:removeRedundantOperationsAndExecute->executeOpsTogether->FragmentTransition.startTransitions—>FragmentTransition.configureTransitionsReordered/configureTransitionsOrdered->TransitionManager.beginDelayedTransition->TransitionManager.sceneChangeRunTransition到sceneChangeRunTransition中
private static void sceneChangeRunTransition(final ViewGroup sceneRoot,
final Transition transition) {
if (transition != null && sceneRoot != null) {
MultiListener listener = new MultiListener(transition, sceneRoot);
sceneRoot.addOnAttachStateChangeListener(listener);
sceneRoot.getViewTreeObserver().addOnPreDrawListener(listener);
}
}
其中有个addOnPreDrawListener,继续跟进,看一下MultiListener
private static class MultiListener implements ViewTreeObserver.OnPreDrawListener,
View.OnAttachStateChangeListener {
Transition mTransition;
ViewGroup mSceneRoot;
final ViewTreeObserver mViewTreeObserver;
MultiListener(Transition transition, ViewGroup sceneRoot) {
mTransition = transition;
mSceneRoot = sceneRoot;
mViewTreeObserver = mSceneRoot.getViewTreeObserver();
}
..省略若干代码..
@Override
public boolean onPreDraw() {
removeListeners();
..省略若干代码..
mTransition.playTransition(mSceneRoot);
return true;
}
};
跟进到Transition类的playTransition方法:
/**
* Called by TransitionManager to play the transition. This calls
* createAnimators() to set things up and create all of the animations and then
* runAnimations() to actually start the animations.
*/
void playTransition(ViewGroup sceneRoot) {
..省略若干代码..
createAnimators(sceneRoot, mStartValues, mEndValues, mStartValuesList, mEndValuesList);
runAnimators();
}
createAnimators->createAnimator,发现createAnimator是空实现;然后再反向找,从Explode/Slide/Fade中任一一个中查找,找到Visibility中,
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
if (visInfo.visibilityChange
&& (visInfo.startParent != null || visInfo.endParent != null)) {
if (visInfo.fadeIn) {
return onAppear(sceneRoot, startValues, visInfo.startVisibility,
endValues, visInfo.endVisibility);
} else {
return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
endValues, visInfo.endVisibility
);
}
}
return null;
}
public Animator onAppear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
if ((mMode & MODE_IN) != MODE_IN || endValues == null) {
return null;
}
if (startValues == null) {
VisibilityInfo parentVisibilityInfo = null;
View endParent = (View) endValues.view.getParent();
TransitionValues startParentValues = getMatchedTransitionValues(endParent,
false);
TransitionValues endParentValues = getTransitionValues(endParent, false);
parentVisibilityInfo =
getVisibilityChangeInfo(startParentValues, endParentValues);
if (parentVisibilityInfo.visibilityChange) {
return null;
}
}
return onAppear(sceneRoot, endValues.view, startValues, endValues);
}
public Animator onDisappear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
if ((mMode & MODE_OUT) != MODE_OUT) {
return null;
}
if (startValues == null) {
// startValues(and startView) will never be null for disappear transition.
return null;
}
..省略若干代码..
if (overlayView != null) {
// TODO: Need to do this for general case of adding to overlay
final ViewGroupOverlay overlay;
if (!reusingOverlayView) {
overlay = sceneRoot.getOverlay();
int[] screenLoc = (int[]) startValues.values.get(PROPNAME_SCREEN_LOCATION);
int screenX = screenLoc[0];
int screenY = screenLoc[1];
int[] loc = new int[2];
sceneRoot.getLocationOnScreen(loc);
overlayView.offsetLeftAndRight((screenX - loc[0]) - overlayView.getLeft());
overlayView.offsetTopAndBottom((screenY - loc[1]) - overlayView.getTop());
overlay.add(overlayView);
} else {
overlay = null;
}
Animator animator = onDisappear(sceneRoot, overlayView, startValues, endValues);
..省略若干代码..
return animator;
}
if (viewToKeep != null) {
int originalVisibility = viewToKeep.getVisibility();
viewToKeep.setTransitionVisibility(View.VISIBLE);
Animator animator = onDisappear(sceneRoot, viewToKeep, startValues, endValues);
..省略若干代码..
return animator;
}
return null;
}
至此,从replace fragment执行commit开始到自定义的onAppear/onDisappear动画被调用的过程分析完毕。
由于我们执行的fragment的replace操作,所以被replace的fragment(为了方便下面叫fragment1)在disappear的时候,执行的是ViewGroupOverlay部分,从debug的过程看,在上面代码addOnPreDrawListener的时候,被replace的fragment和新的fragment(为了区分称为fragment2)是同时存在的,但是在OnPreDrawListener的onPreDraw方法被执行的时候,fragment1已经被remove了,之后看到的fragment1都是ViewOverlayGroup。