我们今天来聊聊系统是如何来处理过渡动画的。我们从一行最简单的代码开始分析:
Scene scene2 = Scene.getSceneForLayout(rootView, R.layout.scene2, context);
TransitionManager.go(Scene scene, Transition transition)
这里我们先通过布局定义了一个场景,然后通过TransitionManager
进入场景,我们首先来看
Scene.getSceneForLayout:
public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
//缓存layout,避免同一个sence layout被多次的inflate
SparseArray<Scene> scenes = (SparseArray<Scene>) sceneRoot.getTag(
com.android.internal.R.id.scene_layoutid_cache);
if (scenes == null) {
scenes = new SparseArray<Scene>();
sceneRoot.setTagInternal(com.android.internal.R.id.scene_layoutid_cache, scenes);
}
Scene scene = scenes.get(layoutId);
if (scene != null) {
return scene;
} else {
scene = new Scene(sceneRoot, layoutId, context);
scenes.put(layoutId, scene);
return scene;
}
}
产生一个Scene
的代码比较简单,然后我们来看TransitionManager.go()
,go
直接调用changeScene(Scene scene, Transition transition)
:
private static void changeScene(Scene scene, Transition transition) {
//1\. 准备工作,保存当前视图树的状态
sceneChangeSetup(sceneRoot, transitionClone);
//2\. 将当前scene inflate到rootview
scene.enter();
//3\. 开启动画设置
sceneChangeRunTransition(sceneRoot, transitionClone);
}
这里我们可以看到启动一个Transition
动画需要三步,下面一步步来分析。
1. 保存当前视图树的状态
我们在自定义Transiton
动画时,曾经需要复写两个方法,captureStartValues
和captureEndValues
来获取视图树的状态,那么这些方法具体是在那里被调用的呢?
首先我们来看一下sceneChangeSetup
:
private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) {
//正在执行的动画,需要暂停
ArrayList<Transition> runningTransitions = getRunningTransitions().get(sceneRoot);
if (runningTransitions != null && runningTransitions.size() > 0) {
for (Transition runningTransition : runningTransitions) {
runningTransition.pause(sceneRoot);
}
}
//这里赋值为true,表示start 不是一个很好的设计。。。
if (transition != null) {
transition.captureValues(sceneRoot, true);
}
// 如果当前有scene,执行回调
Scene previousScene = Scene.getCurrentScene(sceneRoot);
if (previousScene != null) {
previousScene.exit();
}
}
sceneChangeSetup
先暂停了这个rootView
上的所有Transition
动画,然后调用captureValues
开始记录视图树当前的状态,然后获取rootView
当前的Scene
,如果之前在这个rootViwe
执行过Transition
动画,那么这里就是上一次Transition
动画之后最后的Scene
。
Transition.captureValues
代码如下:
void captureValues(ViewGroup sceneRoot, boolean start) {
if ((mTargetIds.size() > 0 || mTargets.size() > 0)
&& (mTargetNames == null || mTarge