紧接着上一篇介绍了Scene和Transition的基本用法后,这篇开始介绍如何运用这些到转场动画中。从A页面到B页面,再从B页面返回到A页面,这就是一个完整的转场过程。而转场动画就是负责来优雅地协调处理好这个过程的。
Content Transition
Content Transition就是最常见的转场动画了。为了方便大家理解,我们先来上个图。
部分代码:
源Activity:
Slide slide=new Slide();
slide.setDuration(3000);
slide.setSlideEdge(Gravity.BOTTOM);
getWindow().setExitTransition(slide);
Explode explode = new Explode();
explode.setDuration(3000);
explode.setMode(Visibility.MODE_IN);
getWindow().setReenterTransition(explode);
复制代码
目标Activity:
Slide slideEnter=new Slide();
slideEnter.setDuration(1500);
slideEnter.setSlideEdge(Gravity.RIGHT);
getWindow().setEnterTransition(slideEnter);
Slide slide=new Slide();
slide.setDuration(1500);
slide.setSlideEdge(Gravity.RIGHT);
getWindow().setReturnTransition(slide);
复制代码
然后在A页面调用方法跳到B页面:
Intent intent = new Intent(this, BActivity.class);
ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this);
startActivity(intent, activityOptionsCompat.toBundle());
复制代码
可以看到一共可以设置四个Transition:
(1)setExitTransition() - 当A 跳转到 B时,A中的View退出场景的效果(默认Null)
(2)setEnterTransition() - 当A 跳转到 B时,B中的View进入场景的效果(默认Fade)
(3)setReturnTransition() - 当B 返回 A时,B中的View退出场景的效果(默认同EnterTransition)
(4)setReenterTransition() - 当B 返回 A时,A中的View进入场景的效果(默认同ExitTransition)
以上这个过程同样可以看做是Transition作用在Scene上的一系列效果,只不过这里的Scene从上一篇中的单一布局换成了Window。不过细心的同学可能发现了,明明我为四个过程都设置动画效果,可为什么ExitTransition没有生效呢?接下来我们为每个Transition加入监听,看看动画的执行流程。下面是其中一个的代码,其他三个都一样:
Explode explode = new Explode();
explode.setDuration(3000);
explode.setMode(Visibility.MODE_IN);
explode.addListener(new Transition.TransitionListener(){
@Override
public void onTransitionStart(Transition transition) {
Log.d("Transitions--","ReenterTransitionStart");
}
@Override
public void onTransitionEnd(Transition transition) {
Log.d("Transitions--","ReenterTransitionEnd");
}
@Override
public void onTransitionCancel(Transition transition) {
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
});
getWindow().setReenterTransition(explode);
复制代码
再次执行程序,日志信息如下:
原来A页面的退出动画和B页面的进入动画、B页面的返回动画和A页面的重现动画是并行执行的。也就是说A页面的ExitTransition不是没有执行,而是在它执行的时候,B页面已经覆盖上来,并且EnterTransition已经同时在执行了,这时A页面已经不可见了。这也是Android默认的转场动画执行流程。
那问题来了,如果想要串行执行该怎么办呢?
有两种方法:
在设置Transition的时候同时设置不允许Transition重叠,也就是并行执行:
getWindow().setAllowEnterTransitionOverlap(false);
getWindow().setWindowAllowReturnTransitionOverlap(false);
复制代码
或者在主题文件全局设置这个属性,这样无疑更好,即减少了代码又保证了应用视觉效果的统一:
false
false
复制代码
修改后效果如下:
日志也显示现在是串行执行了:
生命周期分析
保持上面的打印信息不变,我们增加两个Activity的生命周期日志信息,串行结果如下:
并行如下:
可以得到如下信息:
在A页面的onPause执行前,ExitTransition就已经开始执行了
Transition不会阻塞BActivity的生命周期,尽管是串行执行的,即使ExitTransition没结束,BActivity已经执行完OnResume了。
ReturnExitTransition需要等到AActivity OnStart执行完才开始执行,而且ReturnExitTransition会阻塞AActivity的生命周期,AActivity的OnResume会等到ReturnExitTransition执行完再执行。关于这点可以简要说明下:直接调用Finish不会有动画直接结束掉,需要执行onBackPressed()才会有ReturnExitTransition。看源码就很明显了:
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
}
if (!mFragments.getFragmentManager().popBackStackImmediate()) {
finishAfterTransition();
}
}
复制代码
总结
最后简单分析下转场动画的大致流程(以slide为例),看过上一篇文章的同学应该很好理解:
1.从DecoerView开始,依次遍历获得当前Window上的视图树里的所有View
2.执行captureStartValues(TransitionValues transitionValues),捕获View开始状态的一些属性(visibility,Parent,LocationOnScree)
3.设置所有的VIew为INVISIBLE。
4.执行captureEndValues(TransitionValues transitionValues),捕获View结束状态的一些属性(visibility,Parent,LocationOnScree)
5.比较属性的不同,创建属性动画。下一个过程就是返回属性动画并执行了。
复制代码
这是ExitTransiton的流程,其他三个也差不多。下一篇将会讲带共享元素的转场动画,也是material design中很有特色的动画了。