Android TransitionManager源码解析

通过上篇文章Android 使用TransitionManager来方便地实现过渡动画
我们知道了TransitionManager.beginDelayedTransition可以快速地实现属性动画效果。
那它是怎么实现的呢? 接下来我们来看下它的源码

public static void beginDelayedTransition(final ViewGroup sceneRoot) {
    beginDelayedTransition(sceneRoot, null);
}

public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
    if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
        if (Transition.DBG) {
            Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
                    sceneRoot + ", " + transition);
        }
        sPendingTransitions.add(sceneRoot);
        if (transition == null) {
        	//transition为null,赋值为sDefaultTransition
        	//sDefaultTransition是AutoTransition,是Transition的子类
            transition = sDefaultTransition;
        }
        final Transition transitionClone = transition.clone();
        sceneChangeSetup(sceneRoot, transitionClone);
        Scene.setCurrentScene(sceneRoot, null);
        sceneChangeRunTransition(sceneRoot, transitionClone);
    }
}

可以看到,如果Transition 不传,会赋值为sDefaultTransition,sDefaultTransition是一个AutoTransition,继承自Transition。

Transition有几个重要的方法
记录开始时候的属性
captureStartValues(TransitionValues transitionValues);

记录结束时候的属性
captureEndValues(TransitionValues transitionValues);

创建动画
createAnimators()

播放动画
runAnimators()

可以看到,AutoTransition中,添加了Face

private void init() {
	setOrdering(ORDERING_SEQUENTIAL);
	addTransition(new Fade(Fade.OUT)).
	addTransition(new ChangeBounds()).
	addTransition(new Fade(Fade.IN));
}

而Fade是继承自android.transition.Visibility

@Override
public void captureStartValues(TransitionValues transitionValues) {
   captureValues(transitionValues);
}
private void captureValues(TransitionValues transitionValues) {
   //获取透明度
   int visibility = transitionValues.view.getVisibility();
   //保存到transitionValues这个Map中
   transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
   transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
   int[] loc = new int[2];
   transitionValues.view.getLocationOnScreen(loc);
   transitionValues.values.put(PROPNAME_SCREEN_LOCATION, loc);
}

可以看到,android.transition.VisibilitycaptureStartValues中,调用了captureValues,而在captureValues中,记录下了当前view的visibility,并保存到了transitionValues这个Map中。

接着我们回来看TransitionManagerbeginDelayedTransition
再贴一遍

public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) {
    if (!sPendingTransitions.contains(sceneRoot) && sceneRoot.isLaidOut()) {
        if (Transition.DBG) {
            Log.d(LOG_TAG, "beginDelayedTransition: root, transition = " +
                    sceneRoot + ", " + transition);
        }
        sPendingTransitions.add(sceneRoot);
        if (transition == null) {
        	//transition为null,赋值为sDefaultTransition
        	//sDefaultTransition是AutoTransition,是Transition的子类
            transition = sDefaultTransition;
        }
        final Transition transitionClone = transition.clone();
        sceneChangeSetup(sceneRoot, transitionClone);
        Scene.setCurrentScene(sceneRoot, null);
        sceneChangeRunTransition(sceneRoot, transitionClone);
    }
}

先来看sceneChangeSetup

private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {

        // Capture current values
        ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);

        if (runningTransitions != null && runningTransitions.size() > 0) {
            for (Transition runningTransition : runningTransitions) {
                runningTransition.pause(sceneRoot);
            }
        }

        if (transition != null) {
            transition.captureValues(sceneRoot, true);
        }

        // Notify previous scene that it is being exited
        Scene previousScene = Scene.getCurrentScene(sceneRoot);
        if (previousScene != null) {
            previousScene.exit();
        }
    }

这里调用了transition.captureValues,我们开看下

void captureValues(ViewGroup sceneRoot, boolean start) {
    clearValues(start);
    if ((mTargetIds.size() > 0 || mTargets.size() > 0)
            && (mTargetNames == null || mTargetNames.isEmpty())
            && (mTargetTypes == null || mTargetTypes.isEmpty())) {
        for (int i = 0; i < mTargetIds.size(); ++i) {
            int id = mTargetIds.get(i);
            View view = sceneRoot.findViewById(id);
            if (view != null) {
                TransitionValues values = new TransitionValues(view);
                if (start) {
                    captureStartValues(values);
                } else {
                    captureEndValues(values);
                }
                values.targetedTransitions.add(this);
                capturePropagationValues(values);
                if (start) {
                    addViewValues(mStartValues, view, values);
                } else {
                    addViewValues(mEndValues, view, values);
                }
            }
        }
        for (int i = 0; i < mTargets.size(); ++i) {
            View view = mTargets.get(i);
            TransitionValues values = new TransitionValues(view);
            if (start) {
                captureStartValues(values);
            } else {
                captureEndValues(values);
            }
            values.targetedTransitions.add(this);
            capturePropagationValues(values);
            if (start) {
                addViewValues(mStartValues, view, values);
            } else {
                addViewValues(mEndValues, view, values);
            }
        }
    } else {
        captureHierarchy(sceneRoot, start);
    }
    if (!start && mNameOverrides != null) {
        int numOverrides = mNameOverrides.size();
        ArrayList<View> overriddenViews = new ArrayList<View>(numOverrides);
        for (int i = 0; i < numOverrides; i++) {
            String fromName = mNameOverrides.keyAt(i);
            overriddenViews.add(mStartValues.nameValues.remove(fromName));
        }
        for (int i = 0; i < numOverrides; i++) {
            View view = overriddenViews.get(i);
            if (view != null) {
                String toName = mNameOverrides.valueAt(i);
                mStartValues.nameValues.put(toName, view);
            }
        }
    }
}

可以看到,这里会根据start这个参数,来调用captureStartValuescaptureEndValues

  • 如果start为true,则调用captureStartValues
  • 如果start为false ,则调用captureEndValues

我们已知道,captureStartValues是记录开始时候的属性,captureEndValues是记录结束时候的属性。
而这里,我们传入的start是true,即sceneChangeSetup方法会去记录开始时候View的属性。

我们再回来看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);
    }
}

可以看到,这里注册了一个MultiListenerMultiListener是实现OnPreDrawListener接口的,我们直接来看MultiListener实现的OnPreDrawListener接口的onPreDraw方法

@Override
public boolean onPreDraw() {
    removeListeners();

    // Don't start the transition if it's no longer pending.
    if (!sPendingTransitions.remove(mSceneRoot)) {
        return true;
    }

    // Add to running list, handle end to remove it
    final ArrayMap<ViewGroup, ArrayList<Transition>> runningTransitions =
            getRunningTransitions();
    ArrayList<Transition> currentTransitions = runningTransitions.get(mSceneRoot);
    ArrayList<Transition> previousRunningTransitions = null;
    if (currentTransitions == null) {
        currentTransitions = new ArrayList<Transition>();
        runningTransitions.put(mSceneRoot, currentTransitions);
    } else if (currentTransitions.size() > 0) {
        previousRunningTransitions = new ArrayList<Transition>(currentTransitions);
    }
    currentTransitions.add(mTransition);
    mTransition.addListener(new TransitionListenerAdapter() {
        @Override
        public void onTransitionEnd(Transition transition) {
            ArrayList<Transition> currentTransitions =
                    runningTransitions.get(mSceneRoot);
            currentTransitions.remove(transition);
            transition.removeListener(this);
        }
    });
    mTransition.captureValues(mSceneRoot, false);
    if (previousRunningTransitions != null) {
        for (Transition runningTransition : previousRunningTransitions) {
            runningTransition.resume(mSceneRoot);
        }
    }
    mTransition.playTransition(mSceneRoot);

    return true;
}
};

可以看到,这里也会调用mTransition.captureValues(mSceneRoot, false);,这里的start传的是false,也就是说,这里会记录结束情况下View的数学。

接着,会调用 mTransition.playTransition(mSceneRoot);

void playTransition(ViewGroup sceneRoot) {
    mStartValuesList = new ArrayList<TransitionValues>();
    mEndValuesList = new ArrayList<TransitionValues>();
    matchStartAndEnd(mStartValues, mEndValues);

    ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
    int numOldAnims = runningAnimators.size();
    WindowId windowId = sceneRoot.getWindowId();
    for (int i = numOldAnims - 1; i >= 0; i--) {
        Animator anim = runningAnimators.keyAt(i);
        if (anim != null) {
            AnimationInfo oldInfo = runningAnimators.get(anim);
            if (oldInfo != null && oldInfo.view != null && oldInfo.windowId == windowId) {
                TransitionValues oldValues = oldInfo.values;
                View oldView = oldInfo.view;
                TransitionValues startValues = getTransitionValues(oldView, true);
                TransitionValues endValues = getMatchedTransitionValues(oldView, true);
                if (startValues == null && endValues == null) {
                    endValues = mEndValues.viewValues.get(oldView);
                }
                boolean cancel = (startValues != null || endValues != null) &&
                        oldInfo.transition.isTransitionRequired(oldValues, endValues);
                if (cancel) {
                    if (anim.isRunning() || anim.isStarted()) {
                        if (DBG) {
                            Log.d(LOG_TAG, "Canceling anim " + anim);
                        }
                        anim.cancel();
                    } else {
                        if (DBG) {
                            Log.d(LOG_TAG, "removing anim from info list: " + anim);
                        }
                        runningAnimators.remove(anim);
                    }
                }
            }
        }
    }

    createAnimators(sceneRoot, mStartValues, mEndValues, mStartValuesList, mEndValuesList);
    runAnimators();
}

可以看到,这里最终会调用createAnimators创建动画,并调用runAnimators来执行动画。

至此,beginDelayedTransition的源码,我们就分析完了。
主要有如下几个的步骤:

  1. 记录开始场景的属性
  2. 记录结束场景的属性
  3. 创建属性动画并进行播放
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值