本文原项目地址为:
https://github.com/lgvalle/Material-Animations
在文章最后,有我自己对着这个项目手敲的一份。
代码基本一模一样,只有略微的修改,加了一些注释,以及将其中大多数英文翻译成了中文。
此篇 API 均为 Android 5.0(API 级别 21) 以上才可支持。
此demo一共分为四部分:
1.1 普通过渡 Transition;
1.2 Shared Elements Transition 共享元素;
2.0 TransitionManager 控制动画;
3.0 ViewAnimationUtils 显示或隐藏效果。
过渡效果 Transition
Material Design 为应用中的切换页面时,提供了非常优雅的视觉切换效果。
您可为进入、退出转换、页面之间的共享元素转换设置特定的动画。
1. Transition 动画都包含哪些?
Android 5.0(API 级别 21)支持的进入与退出转换有三个:
Explode | Slide | Fade |
---|---|---|
从中心移入或移出 | 从边缘移入或移出 | 调整透明度产生渐变 |
一会看到使用场景的时候,就会发现上面的三张图,每张图都经历了:(此处可以一会再回过头来看)
退出 -> 进入 -> 返回 -> 重新进入 Exit -> Enter -> Return -> Reenter **第一个页面设置:** android:windowExitTransition 启动新 Activity ,此页面退出的动画 android:windowReenterTransition 重新进入的动画。即第二次进入,可以和首次进入不一样。 **第二个页面设置:** android:windowEnterTransition 首次进入显示的动画 android:windowReturnTransition 调用 finishAfterTransition() 退出时,此页面退出的动画 如此即可达到以上效果。
explode:从场景的中心移入或移出
slide:从场景的边缘移入或移出
fade:调整透明度产生渐变效果
这三个类都继承于 Transition ,所有有一些属性都是共同的。
常用属性如下:
// 设置动画的时间。类型:long transition.setDuration(); // 设置修饰动画,定义动画的变化率,具体设置往下翻就看到了 transition.setInterpolator(); // 设置动画开始时间,延迟n毫秒播放。类型:long transition.setStartDelay(); // 设置动画的运行路径 transition.setPathMotion(); // 改变动画 出现/消失 的模式。Visibility.MODE_IN:进入;Visibility.MODE_OUT:退出。 transition.setMode(); // 设置动画的监听事件 transition.addListener()
至于例子,在下一个给出。
喏,这不就是了。
2. 修饰动画,定义动画的变化率(Interpolator)
在 Java 代码中定义:
Explode transition = new Explode(); transition.setDuration(500); transition.setInterpolator(new AccelerateInterpolator());
在 Xml 资源定义:
<explode android:duration="@integer/anim_duration_long" android:interpolator="@android:interpolator/bounce" />
可选类型:
AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速 AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速 AnticipateInterpolator 开始的时候向后然后向前甩 AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值 BounceInterpolator 动画结束的时候弹起 CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线 DecelerateInterpolator 在动画开始的地方快然后慢 LinearInterpolator 以常量速率改变 OvershootInterpolator 向前甩一定值后再回到原来位置
3. 设置 Transition 的时机
到底该什么时候,设置什么样的过渡呢?
以下为动画的设置场景:
首先打开页面A :
页面A -> Enter 首次进入
从 A 打开 B :
页面A -> Exit 退出
页面B -> Enter 首次进入
从 B 返回 A :
页面B -> Return 返回
页面A -> Reenter 重新进入
可设置的方法如下:
android:windowContentTransitions 允许使用transitions android:windowAllowEnterTransitionOverlap 是否覆盖执行,其实可以理解成前后两个页面是同步执行还是顺序执行 android:windowAllowReturnTransitionOverlap 与上面相同。即上一个设置了退出动画,这个设置了进入动画,两者是否同时执行。 android:windowContentTransitionManager 引用TransitionManager XML资源,定义不同窗口内容之间的所需转换。 android:windowEnterTransition 首次进入显示的动画 android:windowExitTransition 启动新 Activity ,此页面退出的动画 android:windowReenterTransition 重新进入的动画。即第二次进入,可以和首次进入不一样。 android:windowReturnTransition 调用 finishAfterTransition() 退出时,此页面退出的动画 android:windowSharedElementsUseOverlay 指示共享元素在转换期间是否应使用叠加层。 android:windowSharedElementEnterTransition 首次进入显示的动画 android:windowSharedElementExitTransition 启动新 Activity ,此页面退出的动画 android:windowSharedElementReenterTransition 重新进入的动画。即第二次进入,可以和首次进入不一样。 android:windowSharedElementReturnTransition 调用 finishAfterTransition() 退出时,此页面退出的动画
以上为 style 中设置属性,在代码中设置为:
getWindow().setEnterTransition(visibility); // 其余的都是类似
4. 跳转页面
至此,用以上知识基本可以设置出绝大多数的过渡效果。
然后,跳转页面跟普通的跳转也有点不一样。
跳转页面:
protected void transitionTo(Intent i) { ActivityOptionsCompat transitionActivityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(this); startActivity(i, transitionActivityOptions.toBundle()); }
退出页面:
private void closeActivity(){ // 如果定义了 return transition ,将使用 定义的动画过渡 Visibility returnTransition = buildReturnTransition(); getWindow().setReturnTransition(returnTransition); // 如果没有 return transition 被定义,将使用 反进入 的动画 finishAfterTransition(); }
注意:退出时,一定要调用:finishAfterTransition();
通过以上设置,就能够完成一个基本的过渡效果了。
Shared Elements Transition 共享元素
效果如图:
Shared Elements Transition
共享元素的各种设置 与 普通Transition 差不多。
来说说不同的地方。
携带需要共享的 View 进行跳转
也就是在跳转的参数中,增加了要共享的 View控件。
代码如下:
protected void transitionTo(Intent i) { ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, Pair.create(view1, "agreedName1"), Pair.create(view2, "agreedName2")); startActivity(i, options.toBundle()); }
增加的参数的介绍:
Pair.create( View view, // 本页面要共享的 View String resId // 下一个页面的 View 的 id,注意是 id 的字符串 )
页面切换时,动画的效果设置
Android 5.0(API 级别 21)支持转换效果如下:
changeBounds - 改变目标视图的布局边界
changeClipBounds - 裁剪目标视图边界
changeTransform - 改变目标视图的缩放比例和旋转角度
changeImageTransform - 改变目标图片的大小和缩放比例
设置代码:
Slide slide = new Slide(); slide.setDuration(500); ChangeBounds changeBounds = new ChangeBounds(); changeBounds.setDuration(500); getWindow().setEnterTransition(slide); getWindow().setSharedElementEnterTransition(changeBounds);
Shared Elements Transition 就是 特殊的 Transition 用法,都是一样的。
TransitionManager 控制动画
这个框架可以让一些复杂的动画特别简单的被实现。
TransitionManager
简单的说明一下步骤:
定义需要切换 layout xml页面;
调用 Scene.getSceneForLayout() 保存每个Layout;
调用 TransitionManager.go(scene1, new ChangeBounds()) 切换。
相当于定义了不同的 xml 布局,然后通过简单的调用,就完成了较为复杂的动画。
以下为代码片段:
private void setupLayout() { scene0 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene0, this); scene1 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene1, this); scene2 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene2, this); scene3 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene3, this); scene4 = Scene.getSceneForLayout(binding.sceneRoot, R.layout.activity_animations_scene4, this); binding.sample3Button1.setOnClickListener(this); binding.sample3Button2.setOnClickListener(this); binding.sample3Button3.setOnClickListener(this); binding.sample3Button4.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.sample3_button1: TransitionManager.go(scene1, new ChangeBounds()); break; case R.id.sample3_button2: TransitionManager.go(scene2, TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds)); break; case R.id.sample3_button3: TransitionManager.go(scene3,TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential)); break; case R.id.sample3_button4: TransitionManager.go(scene3,TransitionInflater.from(this).inflateTransition(R.transition.slide_and_changebounds_sequential_with_interpolators)); break; } }
只需要定义布局,调用调转,
就实现了,点击四个 Button ,分别切换四个布局。
TransitionManager.go() 中可以设置各种动画。
CircularReveal 显示或隐藏 的效果
ViewAnimationUtils.createCircularReveal()
当您显示或隐藏一组 UI 元素时,Circular Reveal 可为用户提供视觉连续性
CircularReveal
参数说明:
Animator createCircularReveal (View view, // 将要变化的 View int centerX, // 动画圆的中心的x坐标 int centerY, // 动画圆的中心的y坐标 float startRadius, // 动画圆的起始半径 float endRadius // 动画圆的结束半径 )
显示 View :
private void animShow() { View myView = findViewById(R.id.my_view); // 从 View 的中心开始 int cx = (myView.getLeft() + myView.getRight()) / 2; int cy = (myView.getTop() + myView.getBottom()) / 2; int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); //为此视图创建动画设计(起始半径为零) Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); // 使视图可见并启动动画 myView.setVisibility(View.VISIBLE); anim.start(); }
隐藏 View :
private void animHide() { final View myView = findViewById(R.id.my_view); int cx = (myView.getLeft() + myView.getRight()) / 2; int cy = (myView.getTop() + myView.getBottom()) / 2; int initialRadius = myView.getWidth(); // 半径 从 viewWidth -> 0 Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); myView.setVisibility(View.INVISIBLE); } }); anim.start(); }
因为,这些炫酷的效果都只支持 API 23 以上,所以在我们常用的 APP 中都还不常见。但是效果真的很不错。
值得大家研究一下。
此文是我的一个总结。
项目地址:
https://github.com/Wing-Li/Material-Animations-CN
作者:Wing_Li