[MarkDown]Fragment Transition调用过程

背景

    为了实现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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值