屏幕上的对象通常需要由于用户交互或后台处理而重新定位。与其立即更新对象的位置(这会导致它在一个区域闪烁到另一个区域),不如使用动画将其从起始位置移动到结束位置。
Android 允许您在屏幕上重新定位视图对象的一种方法是使用 ObjectAnimator
。您提供对象想要设置到的最终位置以及动画的持续时间。您还可以使用时间插值器来控制动画的加速或减速。
使用 ObjectAnimator 更改视图位置
ObjectAnimator
API 提供了一种方法,可以使用指定的持续时间更改视图的属性。它包含静态方法来创建 ObjectAnimator
的实例,具体取决于您正在设置动画的属性类型。在重新定位屏幕上的视图时,请使用 translationX
和 translationY
属性。
这是一个 ObjectAnimator
的示例,它在 2 秒内将视图移动到屏幕左侧 100 像素的位置
Kotlin
ObjectAnimator.ofFloat(view, "translationX", 100f).apply { duration = 2000 start() }
Java
ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f); animation.setDuration(2000); animation.start();
此示例使用 ObjectAnimator.ofFloat()
方法,因为平移值必须是浮点数。第一个参数是要设置动画的视图。第二个参数是您正在设置动画的属性。由于视图需要水平移动,因此使用 translationX
属性。最后一个参数是动画的结束值。在此示例中,值 100 表示屏幕左侧许多像素的位置。
下一个方法指定动画持续多长时间(以毫秒为单位)。在此示例中,动画运行 2 秒(2000 毫秒)。
最后一个方法使动画运行,从而更新屏幕上视图的位置。
有关使用 ObjectAnimator
的更多信息,请参阅 使用 ObjectAnimator 设置动画。
添加曲线运动
虽然使用 ObjectAnimator
很方便,但默认情况下,它会沿着起始点和结束点之间的直线重新定位视图。Material Design 依赖于屏幕上对象的空间移动和动画的时机曲线。使用曲线运动可以让您的应用更具质感,同时使您的动画更有趣。
定义您自己的路径
ObjectAnimator
类具有构造函数,允许您使用两个或多个属性以及路径同时设置坐标的动画。例如,以下动画器使用 Path
对象来设置视图的 X 和 Y 属性的动画
Kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val path = Path().apply { arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true) } val animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path).apply { duration = 2000 start() } } else { // Create animator without using curved path }
Java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Path path = new Path(); path.arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true); ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); animator.setDuration(2000); animator.start(); } else { // Create animator without using curved path }
以下是弧形动画的外观
图 1. 曲线路径动画。
Interpolator
是缓动曲线的实现。有关缓动曲线概念的更多信息,请参阅 Material Design 文档。Interpolator
定义了动画中的特定值如何作为时间的函数计算。系统为 Material Design 规范中的三个基本曲线提供了 XML 资源
@interpolator/fast_out_linear_in.xml
@interpolator/fast_out_slow_in.xml
@interpolator/linear_out_slow_in.xml
使用 PathInterpolator
PathInterpolator
类是 Android 5.0(API 21)中引入的插值器。它基于 贝塞尔曲线 或 Path
对象。Material Design 缓动文档中的 Android 示例 使用 PathInterpolator
。
PathInterpolator
具有基于不同类型贝塞尔曲线的构造函数。所有贝塞尔曲线都分别在 (0,0)
和 (1,1)
处固定起始点和结束点。其他构造函数参数取决于正在创建的贝塞尔曲线类型。
例如,对于二次贝塞尔曲线,只需要一个控制点的 X 和 Y 坐标
Kotlin
val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { PathInterpolator(0.67f, 0.33f) } else { LinearInterpolator() }
Java
Interpolator myInterpolator = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { myInterpolator = new PathInterpolator(0.67f, 0.33f); } else { myInterpolator = new LinearInterpolator(); }
这会产生一个缓动曲线,该曲线一开始很快,然后在接近结束时减速。
三次贝塞尔构造函数类似地具有固定的起始点和结束点,但它需要两个控制点
Kotlin
val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f) } else { LinearInterpolator() }
Java
Interpolator myInterpolator = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { myInterpolator = new PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f); } else { myInterpolator = new LinearInterpolator(); }
这是 Material Design 强调减速 缓动曲线的实现。
为了获得更大的控制力,可以使用任意 Path
来定义曲线
Kotlin
val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val path = Path().apply { moveTo(0.0f, 0.0f) cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f) } PathInterpolator(path) } else { LinearInterpolator() }
Java
Interpolator myInterpolator = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Path path = new Path(); path.moveTo(0.0f, 0.0f); path.cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f); myInterpolator = new PathInterpolator(path); } else { myInterpolator = new LinearInterpolator(); }
这会产生与三次贝塞尔示例相同的缓动曲线,但它使用 Path
代替。
您还可以将路径插值器定义为 XML 资源
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="0.5"
android:controlY1="0.7"
android:controlX2="0.1f"
android:controlY2="1.0f"/>
创建 PathInterpolator
对象后,您可以将其传递给 Animator.setInterpolator()
方法。Animator
使用插值器在启动时确定时间或路径曲线。
Kotlin
val animation = ObjectAnimator.ofFloat(view, "translationX", 100f).apply { interpolator = myInterpolator start() }
Java
ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f); animation.setInterpolator(myInterpolator); animation.start();