欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android TransitionManager源码解析

程序员文章站 2022-04-19 09:35:40
通过上篇文章Android 使用TransitionManager来方便地实现过渡动画我们知道了TransitionManager.beginDelayedTransition可以快速地实现属性动画效果。那它是怎么实现的呢? 接下来我们来看下它的源码public static void beginDelayedTransition(final ViewGroup sceneRoot) { beginDelayedTransition(sceneRoot, null);}public st...

通过上篇文章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. 创建属性动画并进行播放

本文地址:https://blog.csdn.net/EthanCo/article/details/107456112

相关标签: Android深度