我们可以为Activity的进入和退出过度设置动画,以及Activity之间过渡时指定共享元素的自定义动画,其中:
-
进入 - 是控制Activity中的视图如何进入场景。例如,通过“爆炸式”的效果让视图从外场进入并飞向屏幕中心。
-
退出 - 是控制Activity中的视图如何退出场景。例如,通过“爆炸式”的效果让视图从屏幕中心离开。
-
共享元素 - 是控制两个Activity共享的视图如何在这些Activity之间过渡。例如,如果两个Activity使用相同的图片(但位置和大小不同),Activity之间进行过渡时,changeImageTransform就能使共享元素在过度过程中流畅地平移和缩放图片。
Android 支持以下进入和退出过渡:
- 爆炸式 - 将视图移入场景中心或从中移出。
- 滑动式 - 将视图从场景的其中一个边缘移入或移出。
- 淡入淡出式 - 通过更改视图的不透明度,在场景中添加视图或从中移除视图。
Android 还支持以下共享元素过渡:
- changeBounds - 为目标视图布局边界的变化添加动画效果。
- changeClipBounds - 为目标视图裁剪边界的变化添加动画效果。
- changeTransform - 为目标视图缩放和旋转方面的变化添加动画效果。
- changeImageTransform - 为目标图片尺寸和缩放方面的变化添加动画效果。
下面以进入过度-爆炸式为例,我们来看下效果:
进入过度实现
- 我们启用窗口内容过渡,注意Activity过渡API仅支持Android 5.0 (API 21)及更高版本。我们可以在Activity#onCreate 中直接代码设置:
/* ActivityB.java */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// 启用窗口内容过度
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
// 设置进入过度效果-爆炸式
getWindow().setEnterTransition(new Explode());
// 从当前Activity返回上个Activity时,采用默认过度效果
getWindow().setReturnTransition(new AutoTransition());
}
当然我们也可以直接在values-v21/styles.xml中设置:
<item name="android:windowActivityTransitions">true</item>
<!-- specify enter and exit transitions -->
<item name="android:windowEnterTransition">@transition/explode_transition</item>
<item name="android:windowExitTransition">@transition/explode</item>
其中res/transition/explode_transition.xml见下:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<explode/>
</transitionSet>
其中res/transition/auto_transition.xml见下:
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<autoTransition/>
</transitionSet>
- 启动使用过渡的Activity,在此例中,我们从ActivityA->ActivityB,有代码:
/* ActivityA.java */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
}
退出过度实现
退出过渡实现,与进入过度的实现一样,就不重复写了,退出-爆炸式的方法如下:
getWindow().setExitTransition(new Explode());
这是ActivityA->ActivityB时,ActivityA的退出过渡效果:
共享元素过度实现
我们要在含有共享元素的两个Activity之间添加屏幕过渡动画,一般需要如下操作:
-
在主题背景中启用窗口内容过渡。
-
在样式中指定共享元素过渡效果。
-
定义相应过渡效果的XML资源。
-
使用 android:transitionName 属性为两个布局中的共享元素指定一个通用名称。
-
调用 ActivityOptions.makeSceneTransitionAnimation() 函数。
我们先来看一个共享元素过渡的效果:
我们先在values-v21/styles.xml中,启用窗口内容过渡,并指定共享元素过渡效果:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowSharedElementEnterTransition">
@transition/change_bounds_image_transition
</item>
<item name="android:windowSharedElementExitTransition">
@transition/change_bounds_image_transition
</item>
</style>
其次我们定义change_bounds_image_transition.xml:
<!-- res/transition/change_bounds_image_transition.xml -->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds />
<changeImageTransform />
</transitionSet>
随后我们使用android:transitionName属性为两个布局中的共享元素指定一个通用名称,在ActivityA中如下:
/* ActivityA.java , 并为其 layout中的imageview和textview 设置一个名称 */
@SuppressWarnings("unchecked")
ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation(
IndexActivity.this,
/* imageview_item : "detail:header:image" */
new Pair<>(view.findViewById(R.id.imageview_item),
DetailActivity.VIEW_NAME_HEADER_IMAGE),
/* textview_name : "detail:header:title" */
new Pair<>(view.findViewById(R.id.textview_name),
DetailActivity.VIEW_NAME_HEADER_TITLE));
我们再为ActivityB内的共享元素指定相同名称:
/* ActivityB.java , 指定共享元素名称,与ActivityA一致 */
mHeaderImageView = findViewById(R.id.imageview_header);
mHeaderTitle = findViewById(R.id.textview_title);
/* mHeaderImageView : "detail:header:image" */
ViewCompat.setTransitionName(mHeaderImageView, VIEW_NAME_HEADER_IMAGE);
/* mHeaderTitle : "detail:header:title" */
ViewCompat.setTransitionName(mHeaderTitle, VIEW_NAME_HEADER_TITLE);
启动跳转ActivityA->ActivityB即可:
ActivityCompat.startActivity(IndexActivity.this, intent, activityOptions.toBundle());
note
在代码完成后,发现上面的共享元素效果,不设置transition也没有影响,这是为何呢?获取了下Transition,发现有数据:
final Transition transition = getWindow().getSharedElementEnterTransition();
// transition.mTranstions size = 4 :
// 1.ChangeBounds@9784d13
// 2.ChangeTransform@f66cb50
// 3.ChangeClipBounds@972149
// 4.ChangeImageTransform@3f39a4e
这应该是在源码内android.R.styleable#Window_windowSharedElementEnterTransition有默认实现了吧。
代码我都放在github上了,如想对于过渡动画有个更具体的了解,也可查看google developer 官网。下节我会再介绍下Lottie动画库是如何实现的,敬请期待吧。
本文到这里就结束了,希望对你有帮助。