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
@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.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
方法
@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
的源码,我们就分析完了。
主要有如下几个的步骤:
- 记录开始场景的属性
- 记录结束场景的属性
- 创建属性动画并进行播放
更多相关文章
- Android布局属性
- Android如何保持屏幕常亮
- android 中动画
- android系统学习笔记四
- android -调用系统的拍照程序
- Android如何保持屏幕常亮
- Unity与Android调用交互
- 面试官:作为Android高级攻城狮,请你解释一下 android:text 到 Text
- Android高手进阶教程(四)之----Android(安卓)中自定义属性(attr.