前言
Android新引入的过渡动画主要使用TransitionManager来实现,主要的实现接口就是go和beginDelayedTransition两个方法。为了能够更好的理解过渡动画的实现机制,现在来分析一下它的实现代码,现在先从go方法开始查看内部的实现。
代码分析
找到TransitionManager.go的实现代码,它又调用了changeScene方法,并且传递进了sDefaultTransition过渡动画。
public static void go(Scene scene) {
changeScene(scene, sDefaultTransition);
}
changeScene方法内部首先取出了做过渡动画的根布局,然后判断当前根部局有没有已经提交等待了,第一执行sPendingTransitions肯定没有包含当前根布局。由于transition不为空走的就是else里的逻辑,先将根布局加入到等待过渡列表中然后克隆出一个全新的Transition动画,为动画设置根布局对象。
private static void changeScene(Scene scene, Transition transition) {
final ViewGroup sceneRoot = scene.getSceneRoot();
if (!sPendingTransitions.contains(sceneRoot)) {
if (transition == null) {
scene.enter();
} else {
sPendingTransitions.add(sceneRoot);
Transition transitionClone = transition.clone();
transitionClone.setSceneRoot(sceneRoot);
Scene oldScene = Scene.getCurrentScene(sceneRoot);
if (oldScene != null && oldScene.isCreatedFromLayoutResource()) {
transitionClone.setCanRemoveViews(true);
}
sceneChangeSetup(sceneRoot, transitionClone);
scene.enter();
sceneChangeRunTransition(sceneRoot, transitionClone);
}
}
}
接下来调用getCurrentScene查看以前保留的Scene对象,第一次调用当然也是没有的,后面就开始调用sceneChangeSetup方法了。
// Scene类方法
static Scene getCurrentScene(View view) {
return (Scene) view.getTag(com.android.internal.R.id.current_scene);
}
// TransitionManager的类方法
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();
}
}
由于是第一次调用runningTransitions和previousScene都是空不会执行后面if里的代码,不过这里调用了transition.captureValues(sceneRoot, true);方法,这个方法就是用来记录下开始Scene里的所有子控件在开始状态下的各种属性值。由于还是第一次调用,所以mTargets里面的数据都是空数据,最终直接调用了captureHierachy方法。
oid captureValues(ViewGroup sceneRoot, boolean start) {
clearValues(start);
// mTargetIds第一次执行时候是空的
if ((mTargetIds.size() > 0 || mTargets.size() > 0)
....
} else {
// 执行的是captureHierarchy
captureHierarchy(sceneRoot, start);
}
if (!start && mNameOverrides != null) {
int numOverrides = mNameOverrides.size();
ArrayList<View> overriddenViews = new ArrayList<View>(numOverrides);
for (