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.Visibility
的captureStartValues
中,调用了captureValues
,而在captureValues
中,记录下了当前view的visibility,并保存到了transitionValues这个Map中。
接着我们回来看TransitionManager
的beginDelayedTransition
再贴一遍
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
这个参数,来调用captureStartValues
和captureEndValues
。
- 如果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);
}
}
可以看到,这里注册了一个MultiListener
,MultiListener
是实现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
的源码,我们就分析完了。
主要有如下几个的步骤:
- 记录开始场景的属性
- 记录结束场景的属性
- 创建属性动画并进行播放
本文地址:https://blog.csdn.net/EthanCo/article/details/107456112
推荐阅读
-
axios 源码解析(下) 拦截器的详解
-
Spring源码解析之ConfigurableApplicationContext
-
angularjs 源码解析之injector
-
angularjs 源码解析之scope
-
netty源码解析(4.0)-28 ByteBuf内存池:PooledByteBufAllocator-把一切组装起来
-
SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - SpringBoot如何实现SpringMvc的?
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
android 解析json数据格式的方法
-
Android Intent的几种用法详细解析
-
Java并发之ReentrantLock类源码解析