深入理解Android L新特性之 页面内容&共享元素过渡动画

来源:互联网 发布:与朋友交而不信乎的与 编辑:程序博客网 时间:2024/06/07 02:52

今天我们来聊聊Android L(5.0)引入的新特性:页面内容过渡动画和页面共享动画,这两个特性都是基于我们前面已经说过的Transition动画,如果你对Transition动画不太属性,请先看我前面的两篇文章。在5.0之前,我们从一个Activity A进入到另外一个Activity B时,如果需要设置一个动画,我们通常可以通过overridePendingTransition(int enterAnim, int exitAnim)来设置一个B的进入动画和A的退出动画,但是这个方式的缺点也很明显,我们设置的动画只能针对页面中所有元素。

在5.0以后为了提升Android在页面切换时更好的用户体验,页面间过渡动画应运而生,更加强大灵活的API为开发者提供了更多页面过渡的动画选择。本文的主要内容有:什么是内容过渡动画以及如何使用;什么是共享元素动画以及如何使用;两种动画的原理;最后说了两种共享元素常用场景的实现。

在开始所有内容之前,我首先要请大家树立一个基本原则:页面过渡动画是基于Transition动画来实现的!,文中的所有demo都可以从这里下载。ok,我们进入主题吧。

基本概念

为了简化描述,我们首先定义一些标记,在Activity A打开Activity B这个场景中:

  1. Activity A:我们称它为calling Activity,简称calling
  2. Activity B:我们称为called Activity,以后简称called
  3. calling->called:用来描述calling打开called
  4. called->>calling:用来描述called返回到calling

在页面过渡中,我们有两种动画可以设置:1)页面内容过渡动画,指定整个页面的变化(类似于之前的overridePendingTransition);2)共享元素过渡动画,我们可以指定calling中的一些View平滑过渡到called页面中,下面我们分开讨论这两个东西。

页面内容过渡动画

在内容过渡动画中,我们可以指定四种动画,分别为exit(离开) enter(进入) return(返回) reenter(重新进入),分别对应于下图中的四种状态:


AE4DCA1972E923DB60C7E070F68B2099.jpeg

可以看到 exit  reenter作用在calling Activity上,enter return作用在called Activity上。

和以前一样,我们还是先来一个简单的例子,再次安利一下,本系列文章中的代码都可以从这里直接下载

有人跟我反馈说文章中的gif不知道从哪里开始的,因为它是一直在重复,额从这个例子开始,我会在页面开始加一个begin的黑色页面,同时右下角有时间轴


content_transiton1.gif

我们前面定义过,calling表示第一个页面,called表示第二个页面。

calling->called之后,calling执行了一个淡入淡出的动画,什么?不知道Fade!?,那你先去读一下我的这篇文章-什么是过渡动画。比如,我们在calling中可以直接这样指定:

Fade fade = new Fade();getWindow().setExitTransition(fade);`  //指定退出动画

实际上,这里一共有四个动画:

  1. calling exit: 一个淡出效果,通过Fade实现
  2. called enter:一个从上往下的Slide效果
  3. called return:从左往右消失
  4. calling reenter:从底部往上出现

上面例子中,我们直接指定了四种动画效果。这四种效果是两两一对的:
exit对应reenter, enter对应return。如果我们只指定了exit或者enter,那么与这两个对应的另外一个动画将默认使用关联动画的反向执行。此外,还需要注意一点的是,上例中能够这么看清楚这四个动画的原因是我将动画叠加执行去掉了,你可以通过setAllowEnterTransitionOverlap改变这个设置。

注意,为了启动页面过渡效果,calling需要将startActivity(intent)改成调用startActivity(Intent intent, Bundle options),后面的options可以通过ActivityOptions.makeSceneTransitionAnimation(this).toBundle()来获取;
called中我们需要将调用finish()改成调用finishAfterTransition() 

我们前面说了,这个页面过渡基于Transition来做的,那Transition动画无非就是两点呗:1)记录动画前后的视图树的状态变化;2)定义两个视图树之间的过渡效果。第二条我们前面已经分析过了,现在来看看系统是如何来记录两个场景的不同状态的。
其实对于整个页面的进入和退出,系统采取的办法也很简单,以退出为例,在将calling真正隐藏之前,系统直接调用TransitionManager.beginDelayedTransition(decorView,exitTransition);,然后再调用decorView.setVisibility(INVISIBLE);,这样退出动画就自然执行了。
是不是很简单??

这里其实说明了如果我们自己定义一个过渡动画,那么必须要处理View的可见性变化,因为只有处理了可见性变化才能触发动画,如果不明白这里,可以去查看我前面的文章。

共享元素动画

怎么描述共享元素动画呢?所谓共享就是calling中的一个viewcalled中的一个view可以做一个平滑的过渡,下面动图中的红色的小圆圈就是一个共享元素,在实际应用中,大家可以看一下微信朋友圈图片打开的动画就是一个典型的共享元素动画。


share_transiton.gif

如果仔细的朋友可以看到,我们不仅仅将view在两个页面间共享,而且在共享之前,我们有颜色变化的动画,这里也涉及了四个动画,和之前内容过渡一一对应。
它们分别是

  1. calling share exit: 颜色由红色变成绿色
  2. called share enter:大小由小变大
  3. called share return:大小由大变小
  4. calling share reenter:颜色由绿色变成红色

我们来看一下如何来让两个页面之间的View做一个过渡:

  1. 在两个Activity的布局中为需要进行过渡变化的View设置android:transitionName,android:transitionName必须成对出现。
  2. startActivity时,我们通过startActivity(intent,ActivityOptions.makeSceneTransitionAnimation(this,view,transitionName).toBundle()); 关联两个Activity中间的View。

我在前面曾经让你想想看,我们startActivity的第二个参数的作用是啥,因为共享元素也是基于过渡动画来做的,而我们需要过渡的View又处在两个不同的Activity中,但是一个动画肯定不能在两个Activity中间无缝过渡,那系统是怎么做到的呢?
其实着仅仅是一个障眼法而已,比如上面例子中,我们将一个Viewcalling移动到了called,但是实际上这个动画仅仅是在called中执行,而我们startActivity第二个参数的Bundle实际上是将calling中的共享元素的相关信息传递给calledcalled在进入时,会先吧这些共享元素的信息取出来,然后在直接操作当前视图树中相关联的View的属性和calling中元素一样,记录一下状态,再恢复成called本来的布局,记录一下状态,然后就可以愉快地开始动画了,真相就是这个样子。
除了Activity,其实Android还提供了Fragment切换时进行页面过渡动画的相关API,和Android完全一致,这里就不去说明了。
Material Design引入了很多UI的新技能,其实本人不太喜欢专研UI方面的东西,但是有时候产品需求压下来,还是得调研,多了解一些新的知识总归是好的。
多谢大家关注这个Transition动画系列,到这里基本上就已经完全结束了,如果你觉得自己有一些收获,请点击底下的LIKE吧!

2016-08-07补充:

在分享元素实战应用中有两个比较重要的场景,官方文档对这个场景的解决方案并不明确,在这里补充一下。

补充一 更新共享元素对应关系

很多情况下,我们需要共享元素的页面满足下面的条件:
calling是一个列表页面,called是一个详情页,我们在列表中选择一项打开,然后会有一个元素共享过渡到详情页,而我们在详情页是可以左右滑动切换元素的,如下图所示:


share_transiton000.gif


这个系统自带的相册APP,可以看到我们进入大图预览时,点击的是图片4,然后我们左右滑动,切换图片之后返回列表页,这个时候过渡动画直接返回到了图片1,那这是怎么做到的呢?

其实这里无非在过渡动画返回时,需要告诉系统,我的绑定关系改变了,我们可以在calling设置一个SharedElementCallback,然后在回调的onMapSharedElements更新一下对应关系,大概的逻辑代码如下:

setExitSharedElementCallback(new SharedElementCallback() {        @Override        public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {            super.onMapSharedElements(names, sharedElements);                  sharedElements.put("avator",getItemByPosition(curentPos));        }    });

我们在celled中左右滑动修改了列表Index之后,需要通过某种方式告知calling,你可以通过startActivityForResult()也可以通过EventBus之类的第三方库,但是需要注意的是,onMapSharedElementsexitreenter时都会触发!

延迟共享元素

想想这种场景吧,called中的共享元素在进入时,并没有到达最终的位置(比如这个数据需要从网络获取数据之后,才展示它真正的大小位置),此时如果过渡动画如果过早的执行,那么过渡动画获取的called中共享view的状态并不正确,所以我们有时候希望called中的共享元素完全layout完毕之后再执行,幸好API提供了支持。

calledonCreate中我们可以这样处理:

@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 延迟共享动画的执行postponeEnterTransition();}

然后在共享元素的最终布局确定后,你可以执行startPostponedEnterTransition来启动共享元素动画,我们一般可以通过下面的工具方法来启动延迟动画:

private void scheduleStartPostponedTransition(final View sharedElement) {sharedElement.getViewTreeObserver().addOnPreDrawListener(    new ViewTreeObserver.OnPreDrawListener() {        @Override        public boolean onPreDraw() {            //启动动画                  sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);            startPostponedEnterTransition();            return true;        }    });}

但是使用延迟共享动画有两点需要注意:
1. 调用postponeEnterTransition必须要在适当的时候调用startPostponedEnterTransition,否则Activity的过渡就会卡到这里,不能执行下去 
2.基于1,我们在这两个方法间实际上也不能间隔太久(前面说的等待网络返回只是举个例子,不要在实际上使用等待网络返回的共享元素),如果间隔太大,那页面的过渡会直到调用startPostponedEnterTransition才能进行页面切换!

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 装修预留插座被挡了一半怎么办 衣服放在柜子里面有味道怎么办 河北发货一个柜到天津港口怎么办 家用潜水泵更换电容后压力小怎么办 无塔供水井水水位低了怎么办 应急部成立林场的专业灭火队怎么办 路由器我恢复出厂设置断网了怎么办 多囊卵巢综合症不来月经怎么办 天刀普通血战苍梧城没有太白怎么办 天涯明月刀把沈妄言打入水中怎么办 天涯明月刀刷本队友技能太花怎么办 手机收所有短信时显示被隐藏怎么办 div放图片多出的空白怎么办 我14岁射精让我记忆力差了怎么办 qq闪退聊天记录全没了怎么办 木瓜奇迹忘记升级过头转职了怎么办 孩子进入青春期什么坏事都干怎么办 母狗狗第一次来月经应该怎么办图 社保断了想补缴怎么办?这些要知道 换工作社保断了一个月怎么办 北京社保中间断了几个月怎么办 农保和社保都交了医保怎么办 如果交了社保结婚生孩子断了怎么办 南京社保中间断了几个月怎么办 mu大师等级技能点加点太慢怎么办 永恒纪元戒不是本职业套装石怎么办 全民奇迹忘记在哪个区了怎么办 全民奇迹安卓的忘记那个区了怎么办 大天使之剑h5所在服人少怎么办 买的裙子因为好看没有勇气穿怎么办 魅蓝s6锁屏密码忘了怎么办 u盘被占用不能安全弹出怎么办 洛克王国得到了魔攻巨蟹座怎么办 在育碧下载游戏下一半不下了怎么办 轩辕传奇单机版忘记哪个区了怎么办 登腾讯游戏动态密码啥意思怎么办 说了不该说的话别人不原谅怎么办 轩辕传奇手游金币用错了怎么办 神秘时代4法杖按键冲突怎么办 孕2个月发烧38度怎么办 不知道怀孕喝了止咳糖浆怎么办?