这是我这个系列的目录,有兴趣的可以看下: android 动画系列 - 目录
专场动画大家熟悉吧,效果绝对炫酷,也是产品汪们动脑筋考研我们的地方,第一效果要炫酷,第二不要卡,简单的专场动画没什么,但是产品要是给你一个复杂的专场动画,那就考验技术功底了,效果要好,速度又要快,真的是有点难度的,所以今天我们来看看这个专场动画,不要有侥幸心理啊,这部分是逃不过去的,必回必备必精的部分。
废话不多说,开始啦,先来理论
何为专场动画
转场动画就是在页面切换时,前一个和后一个页面之间的动画过度,说起来很简单,相信打击也很熟悉,那么我们来说下大家不熟悉的地方。
专场动画的4个状态:
- enter :进入动画
- exit : 退出动画
- reenter : 再次进入动画
- return : 页面关闭动画
举例:
从 A -> B 页面,一个很熟悉的场景吧:
- 对于 A 来说是 exit 动画,因为这时是 A 启动 B ,A 就要切换到后台去,所以是退出动画,注意不是关闭动画
- 对于 B 来说,此时 B 是一个新创建的页面,所以 B 是 enter 进入动画
从 B -> A 页面,点击返回键,回到上个页面
- 对于 A 来说是 reenter 再次进入动画,因为 A 是从后台切换到前台。
- 对于 B 来说是 return 关闭动画,因为这时候 B 页面是要销毁的,所以是关闭动画
清楚了上面转场动画的4个状态,下面再去看就清楚多了。
4.X 时代的传统写法
4.x 时代的传统写法,大家一定太熟悉了把 ,操作的是 view 动画
public void overridePendingTransition(int enterAnim, int exitAnim)
现在再去看这里面的 enter 和 exit 应该就明白是啥意思了吧,之前这里的确是有很多人不清楚的,包括我也是的。
注意点:
- overridePendingTransition方法必须在startActivity()或者finish()方法的后面
- 如果参数是0,表示没有动画,尽量不要传0,enter 传0,会是一个黑屏的效果,亲测
startActivity(intent);
overridePendingTransition(R.anim.bottom_top_anim, R.anim.alpha_hide);
---
finish();
overridePendingTransition(R.anim.alpha_show, R.anim.top_bottom_anim);
另外使用主题也是可以的,注意操作的同样是 view 动画
用这个属性去设置
- @style/ActivityTransitionAnimatoin
这里买的 open 表示 A -> B , close 表示 B -> A
4.x 时代的专场动画没啥好说的,是最简单好用的,产品没什么特殊设计用这个方式就好了。缺点嘛,就是不够灵活,大家发现没,动画添加到谁身上了,是添加到 activity 身上的,所以我们只能给整个页面添加一个统一的动画,而不能针对页面中的控件进行操作。
最简单的我们可以直接使用 android 系统以及给你定义好的动画资源
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
windowAnimation和ActivityAnimation的区别
上面我们使用 activityOpenAnimation / activityCloseAnimation 这是在 activity 身上做动画,我们其实还可以在 window 身上做动画,并且window 的级别高于 activity ,两者同时存在,以 window 动画为准。window 的动画我们可以在 theme 上直接加:
比 activityOpenAnimation / activityCloseAnimation 动画写起来还方便,不用再键一个 style 出来,不过注意啊,只能设置 下一个页面的动画,因为这里我们只能设置 enter / exit 的动画,具体使用哪种看大家具体需求把。
MD 时代
5.X 的时代我们迎来了革命性的 MD ,google 在 apple 的压力下重新优化了 android 系统上的交互体验,最大的改变是带给了 android 很炫酷的交互体验,这些体验是多方位的,知识点也是很多,这里咱们就来看看新的页面专场动画
不就知道大家听过 transition 变换动画没有,这是 API 19时添加的一种动画,叫过度动画,MD 带给我们的心得炫酷的专场动画就是用 transition 变换动画实现的,transition 本身是比较复杂的,本篇我们不说,下篇再介绍。这里简单说下,transition 是对一个 viewgroup 中所有的 view 做动画,transition 是可以设置这个 viewgroup 是哪个的,我们用 transition 作页面转场动画,就是把 transition 中的视图设置为 页面的根视图。
MD 提供了几个 transition 变换动画的默认实现:
- Explode :爆炸效果
- Slide : 侧滑效果
- fade : 淡入效果
- Share Element : 共享元素效果
这几个是 MD 默认提供的专场动画效果,是 transition 的子类或间接子类,本质是生成 animator 动画。
那么我们怎么使用呢,我们需要结合 window 来使用了,API 19 添加了 transition 动画后,我们可以给 window 设置进入和退出4种状态对用的动画:
- setExitTransition() :A中的View退出场景的transition
- setEnterTransition() :使B中的View进入场景的transition
- setReturnTransition() - 当B 返回 A时,使B中的View退出场景的transition
- setReenterTransition() - 当B 返回 A时,使A中的View进入场景的transition
也可以在theme中定义如下style:
- android:windowExitTransition
- android:windowEnterTransition
- android:windowReturnTransition
-
android:windowReenterTransition
Explode
我们需要 new 一个 transition 动画对象,就是这个 Explode 类,然后设置进 window 就好了
启动页面
Intent intent = new Intent(this, ExplodeTransitionActivity.class);
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle();
startActivity(intent, options);
在后一个页面设置切换动画
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Explode explode = new Explode();
getWindow().setEnterTransition(explode);
getWindow().setExitTransition(explode);
setContentView(R.layout.activity_mdtarge);
}
可以看到,Explode 根据视图层次自动决定 view 动画的方向是向上还是向下, Explode 类有几个可以设置的属性:
看上图,可以设置时间,插值器,延迟时间,其他的都是涉及到 transition 比较很细你的知识了,需要去详细学习 transition 才行。
Slide
使用方法和 Explode 一样
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Slide slide = new Slide();
getWindow().setEnterTransition(slide);
getWindow().setExitTransition(slide);
setContentView(R.layout.activity_mdtarge);
Slide 这个动画效果可玩的比较多啊,我们来看看都可以怎么玩
除了时间,插值器,延迟时间外,我们还可以设置滑动方向
Slide slide = new Slide(Gravity.LEFT);
slide.setDuration(500);
Fade
和 Explode ,Slide 是使用上都是一样的,没什么特殊的设置选项
Fade fade = new Fade();
getWindow().setEnterTransition(fade);
getWindow().setExitTransition(fade);
Explode ,Slide,Fade 共同点
为啥我要特意说一下呢,因为这3个 MD 内置效果可以看到用法都一样,都是基于 transition 技术实现页面专场动画的最简单使用。
这里有一个点还要说一下,transition 的转场动画是对页面根节点视图中所有 view 都执行动画,我们可以设置忽略的 view 的 id,那么这个 view 就不会执行转场动画了
忽略底部导航栏 view
slide.excludeTarget(android.R.id.navigationBarBackground, true);
忽略底部状态栏 view
slide.excludeTarget(android.R.id.statusBarBackground, true);
也可以直接在style中设置动画
- @transition/slide_anim
- @transition/slide_anim
其中@transition/slide_anim如下
Share Element
共享元素动画是 MD 中最吸引人的专场动画效果了,这个 apple 绝对没有啊,这个做好了看着绝对上档次,目前也是有很多 app 都集成进来了,但是想做好真不容易,在实际开发中,遇到的问题也是很多啊,我这里也是很欠缺的,比如点击列表的一个 item 跳到一个页,跳到的新的页面里面还是列表,然后在这个心得列表里面点击另一个 item再切回来,怎么正确的关联前后页面的共享元素是个大问题啊。
说简单点就是页面切换的动画是从前一个页面的某些元素开始,渐变到整个第二个页面的,废话不多说,看看效果就知道了
上面的例子里我们关联了前一个页面和后一个页面中的那个机器人图标的 imageview。说来使用起来也是很简单的:
- 在 xml 中设置相同的 transitionName 标记用于执行共享元素动画的 view
android:transitionName="imageView"
- 启动activity B,在启动页面的 bundle 参数中传入共享元素 view 和 transitionName 标记
Intent intent = new Intent(this, ShadeTransitionActivity.class);
Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(this, view_image, view_image.getTransitionName()).toBundle();
startActivity(intent, bundle);
- 在B中设置共享元素动画,这里必要时不设置的话也没事用的是默认的动画样式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TransitionSet set = new TransitionSet();
set.addTransition(new ChangeImageTransform());
set.addTransition(new ChangeBounds());
getWindow().setSharedElementEnterTransition(set);
setContentView(R.layout.activity_mdtarge);
}
简单学下原理:创建出 B 页面对象和 window 后,B 页面解析标签,解析初共享元素,然后和 B 页面的共享元素关联,然后计算出动画的初始参数和结束参数,然后生成动画对象,然后 A 页面隐藏,关闭,B 页面执行这个动画,其中的技术实现是使用 transition 来实现的。
多个共享元素:
Intent intent = new Intent(this, ShadeTransitionActivity.class);
Pair pair1 = new Pair(view_image, ViewCompat.getTransitionName(view_image));
Pair pair2 = new Pair(tx_text, ViewCompat.getTransitionName(tx_text));
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(this, pair1, pair2).toBundle();
startActivity(intent, bundle);
这里使用 ActivityOptionsCompat 创建的这个 bundle 对象,推荐还是用这个兼容类好。
Fragment 的页面切换动画
enter,exit,reenter,return 这4个位置的动画大家看过上面应该知道都是对应哪个位置的了把,fragment 的替换我们一般来说我们有2种常用的方式:
- replace 替换
我们使用上面的图中的方式,加入返回栈就可以实现页面切换的动画 - show,hint
这种方式,我们可以使用添加 transition 的方式实现 页面切换动画
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Slide slide = new Slide(Gravity.LEFT);
Explode explode = new Explode();
setEnterTransition(slide);
setExitTransition(slide);
setReenterTransition( explode );
setReturnTransition( explode );
}
在 fragment 的 onCreate 中添加 transition 动画,我试了下,show,hint 触发的都是 enter,exit 动画,reenter,return 没有触发,这里就麻烦了,要知道 enter,exit,reenter,return 这4个状态是个整个效果,涉及到前后2个页面,这里 reenter,return 触发不出来怎么办,只能让前后2个页面的 enter,exit 执行相反方向的动画了,比如 slide 这个效果,A 页面 left,B 页面 right。
更多的我还得再去找找资料,不过基本的操作就是这样了,fragment 的页面切换我们单纯用的不多,多数使用场景还是在 viewpager 中,vp 的页面切换原理就不是本文写的方式了,是实现 ViewPager.PageTransformer 的这个接口,具体的看这里:ViewPager学习(1) - transformer 页面切换
最后啦
最后了简单的吐槽下吧,这个代码啊,不看不会,不写不明白啊。之前零零散散的关于专场动画这块也是看了还几次了,时间也是花了一些的,时间久一点忘了,就真是一点都不记得了,必须要写 demo,必须要写博客才行,这次看了不少,总算是看全了,以后忘了,10分钟就想起来了。
贴一下本项目的 demo 地址:ActivityTransitionDemo