通过上篇文章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

@Overridepublic 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方法

@Overridepublic 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. 创建属性动画并进行播放

更多相关文章

  1. Android布局属性
  2. Android如何保持屏幕常亮
  3. android 中动画
  4. android系统学习笔记四
  5. android -调用系统的拍照程序
  6. Android如何保持屏幕常亮
  7. Unity与Android调用交互
  8. 面试官:作为Android高级攻城狮,请你解释一下 android:text 到 Text
  9. Android高手进阶教程(四)之----Android(安卓)中自定义属性(attr.

随机推荐

  1. Android P/9.0 http网络请求异常
  2. android activity ImageView全屏设置
  3. Android开发学习笔记之一
  4. 看雪学院-浅入浅出Android安全 笔记
  5. Android SDK安装遇到的问题
  6. Jenkins搭建Android自动打包二之设置渠道
  7. Android之ListViewArrayAdapter,SimpleAd
  8. android - JNI接口函数 (2)
  9. android开发中handler的总结
  10. Android输入系统概述