安卓中的自定义动画和片段间的过渡效果
导航组件是Android Jetpack库的一部分,允许你实现导航,从简单的按钮点击到更复杂的模式。这使得用户可以更容易地从一个目的地导航到另一个目的地。
在Fragments之间来回导航有时会让人困惑。通过自定义过渡动画,如果用户要去一个新的目的地,我们可以添加相应的和描述性的过渡动画。另外,当导航回到前一个片段时,我们可以为这个动作制作动画。
我们可以添加自定义的过渡动画,使对话片段的出现和取消成为动画。此外,我们还可以在我们的应用程序中加入共享的过渡元素,以便在新的目的地打开一个图像。
转场动画一般会改善应用程序的用户体验(UX),有助于留住用户。
前提条件
要完成本教程,你应该具备以下条件。
- 在你的机器上安装了[Android Studio]。
- 具有创建和运行Android应用程序的良好知识。
- [Kotlin]编程语言的基本信息。
- 设置和使用导航组件的基础知识,你可以在[本教程]中学习如何使用导航组件。
过渡动画
过渡动画可以有4种类型。
- 输入-为NavHostFragment带来一个新的片段。
- 退出-从NavHostFragment中删除当前显示的Fragment。
- Pop Enter-当导航返回时,这将带来以前的片段。
- Pop Exit-这将退出Fragment,为前一个Fragment提供可见空间。
我们还可以定义共享的元素过渡,它可以将一个被点击的图像移动到一个新的目的地。当你有图像而你想导航到某个特定图像的细节时,这很有用。图像会扩展到一个新的目的地。
对于对话框,我们可以在它们被显示和解散时对其运动进行动画处理。我们可以定义slide-up 和slide-down 过渡动画。
在翻译不同的元素时,即从左、右、上、下,我们可以在我们的动画资源文件中使用以下属性。
fromXDelta- 表示我们从哪个X轴值开始转换。toXDelta- 表示在X轴上的什么位置。fromYDelta- 表示从Y轴的什么值开始。toYDelta- 表示我们要过渡到Y轴的什么值。duration单位:毫秒 - 这是动画发生的时间。
过渡动画图

从上面的图表来看。
水平过渡 (X-轴)
在0% ,我们可以向右移动,即100% ,也可以向左移动,即-100% 。
- 从
-100%移动到0%,意味着我们的片段从左边进入。我们将利用这一点来进入我们的片段。 - 从
0%移动到100%意味着我们的片段正在向右边移动。你可以用它来退出我们的片段。 - 从
0%移动到-100%意味着我们的片段正在向左边移动。我们将用它来从NavHostFragment中删除当前的Fragment。 - 从
100%移动到0%意味着我们的片段将从右边来。这将被用来带回最初的Fragment。
垂直过渡(Y轴)
在0% ,我们可以移动到顶部,也就是100% ,或者我们可以向下移动到-100% 。
- 从
100%移动到0%,意味着我们的DialogFragment将从底部进入。我们可以用它来创建一个幻灯片动画。 - 从
0%移动到100%意味着我们的DialogFragment将从中心移动到底部。我们可以用它来创建一个下滑动画。 - 从
-100%移动到0%,意味着我们的DialogFragment将从顶部出现。
第1步 - 创建一个动画目录
首先,创建一个新的资源目录并将其命名为anim ,这将存放我们的过渡动画。
第2步 - 创建过渡动画
进入一个片段
这涉及到将一个新的片段带入视图。这个新的片段将从左边进入。因此我们需要创建一个名为from_left 的动画。为此,右键单击动画目录并选择new >> animation layout file 。
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%" android:toXDelta="0%" android:duration="700"/>
</set>
我们从NavHostFragment中移除当前的Fragment,以便新的Fragment可以被看到。Fragment将向右侧退出,我们将创建一个名为to_right 的动画。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="100%" android:duration="700"/>
</set>
导航回前一个Fragment
首先,我们需要移除当前正在显示的Fragment。我们将创建一个名为to_left 的动画,它将向左侧移除片段。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0%" android:toXDelta="-100%" android:duration="700"/>
</set>
把最初的Fragment带回NavHostFragment上。这个Fragment将来自右边,我们将创建一个名为from_right 的动画。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%" android:toXDelta="0%" android:duration="700"/>
</set>
导航回到前一个Fragment是有帮助的,因为顶部的返回按钮也是动画的。
给片段添加动画
为了添加过渡动画,在你的NavGraph ,点击一个你想为其过渡制作动画的Action 。在你的右边,你会看到一个窗格,它有一个添加动画的部分。

对于home Fragment,我们需要指定popEnterAnim 和popExitAnim ,以便相应地对ActionBar/Toolbar 进行动画。
- 在
enterAnim属性中,传递from_leftanim。 - 在
exitAnim中,通过to_rightanim。 - 在
popEnterAnim中传入from_rightanim。 - 在
popExitAnim中传入to_leftanim。
对于其他动作不是导航到新目的地的Fragments,会明确地调用一个返回按钮。
在动画面板中,你将包括。
- 在
popEnterAnim中传递from_rightanim。 - 在
popExitAnim,通过to_leftanim。
第3步 - 创建对话动画
在这一步,我们将看看如何给DialogFragments制作动画。
显示对话框
我们将创建一个名为slide_up 的动画,使我们的对话框从底部到屏幕中央产生动画。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="100%" android:toYDelta="0%" android:duration="300"/>
</set>
关闭对话框
我们将创建一个名为slide_down 的动画,在我们的对话框从屏幕中心移动到底部的过程中为它提供动画。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="0%" android:toYDelta="100%" android:duration="300"/>
</set>
将动画添加到对话框中
为DialogFragment添加动画与普通的Fragments有一点不同。
首先导航到你的res "values 。在你的theme ,定义以下样式。
<style name="DialogFragmentAnimation">
<item name="android:windowEnterAnimation">@anim/slide_up</item>
<item name="android:windowExitAnimation">@anim/slide_down</item>
</style>
然后在你的DialogFragment ,覆盖onActivityCreated 方法并添加我们定义的样式到Dialog。
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
dialog!!.window!!.attributes.windowAnimations = R.style.DialogFragmentAnimation
}
第4步 - 创建共享元素过渡
在这里,一旦图片被点击,我们将导航到另一个Fragment。该图像将在另一个Fragment中扩展到一个更大的图像。
在我们的第一个Fragment布局中,添加一个ImageView 。
我们必须给ImageView一个transitionName - 当使用共享过渡元素时,每个视图都需要有一个独特的transitionName ,这样Android就可以确定它应该在哪些视图上执行过渡。
<ImageView
android:id="@+id/image"
android:layout_width="120dp"
android:layout_height="120dp"
android:transitionName="small_image"
android:src="@drawable/mountain"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/buttonDialog" />
在我们的第二个Fragment布局中,我们还将包括一个ImageView--前一个Fragment中的图像的扩展。
我们还将给它一个不同的过渡名称,即large image ,并给它不同的尺寸,以便它能覆盖3/4的屏幕。
<ImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="550dp"
android:transitionName="large_image"
android:scaleType="centerCrop"
android:src="@drawable/mountain"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
第一个片段的逻辑
在第一个片段中,我们将为ImageView设置一个onClickListener ,并添加以下代码来启动过渡。
binding.image.setOnClickListener {
val extras = FragmentNavigatorExtras(binding.image to "large_image")
findNavController().navigate(R.id action_FragmentOne_to_FragmentThree, null, null, extras)
}
我们创建类型为FragmentNavigatorExtras 的extra,在这里我们传递被点击的ImageView的id ,然后传递我们需要过渡到的过渡名称。最后,我们执行导航并传递额外的内容。
确保你已经在你的NavGraph中创建了一个动作,将第一个片段链接到我们要导航的片段。
第二个片段的逻辑
在另一个Fragment中,我们需要指示我们的动画何时进入或离开。在onCreateView ,包括以下几行代码。
val animation = TransitionInflater.from(requireContext()).inflateTransition(android.R.transition.move)
sharedElementEnterTransition = animation
sharedElementReturnTransition = animation
演示

总结
在本教程中,我们已经了解了什么是过渡动画,以及如何在浏览目的地时添加动画。我们还研究了如何为DialogFragment的过渡制作动画,最后是如何创建一个共享元素的过渡。
来吧,用这些过渡来增强你的安卓项目,以增加你的应用程序的互动性。