基于物理特性 运动是通过力来驱动的。弹簧弹力就是这样一种力 以及互动和动作效果弹簧弹力具有以下属性: 阻尼和刚度。在基于弹簧的动画中,值和 速度是根据对每个物体施加的弹簧弹力计算得出的, 帧。
如果您想让应用的动画只向一个方向减速, 可以考虑使用基于阻力的 投掷动画 。
弹簧动画的生命周期
在基于弹簧的动画中,SpringForce
类可自定义弹簧的刚度、阻尼比以及
最终位置。动画一开始,弹簧弹力就会立即更新
每个帧上的动画值和速度。动画继续播放
直到弹簧弹力达到平衡为止
例如,如果您在屏幕上拖动某个应用图标,之后又松开手指 将手指从图标上松开,图标就会拉回原来的位置 由一个看不见但熟悉的力量制造的地方
图 1 演示了类似的弹簧效果。加号 (+) 添加 圆圈的中部表示通过触摸手势施加的力。
![弹簧释放效果](https://developer.android.google.cn/static/images/guide/topics/graphics/spring-release.gif?authuser=7&hl=sk)
制作弹簧动画
为应用制作弹簧动画的一般步骤如下: 如下所示:
- 添加支持库 您必须将支持库添加到项目中,才能使用弹簧动画类。
- 制作弹簧动画:
主要步骤是创建
SpringAnimation
类,并设置动画效果 行为参数。 - (可选)注册监听器:
注册监听器以监控动画生命周期更改和动画
值更新。
注意:更新监听器应 只有在需要逐帧更新动画值时才注册 更改。更新监听器可防止动画 在单独的线程上运行
- (可选)移除监听器: 移除不再使用的监听器。
- (可选)设置起始值: 自定义动画起始值。
- (可选)设置值范围: 设置动画值范围,将值限制在最小值和最大值范围内。
- (可选)设置起始速度: 设置动画的起始速度。
- (可选)设置弹簧属性: 设置弹簧的阻尼比和刚度。
- (可选)创建自定义弹簧: 如果不打算使用默认弹簧,请创建自定义弹簧 或者想在整个动画过程中使用通用弹簧
- 启动动画: 启动弹簧动画。
- (可选)取消动画: 在用户突然退出应用或视图时取消动画 变得不可见。
以下部分讨论了制造弹簧的常规步骤 动画效果。
添加支持库
要使用基于物理特性的支持库,您必须将支持库添加到项目中 如下所示:
- 打开应用模块的
build.gradle
文件。 将支持库添加到
dependencies
部分。Groovy
dependencies { def dynamicanimation_version = '1.0.0' implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version" }
Kotlin
dependencies { val dynamicanimation_version = "1.0.0" implementation("androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version") }
要查看此库的当前版本,请参阅 版本页面上的 DynamicAnimation。
创建弹簧动画
借助 SpringAnimation
类,您可以创建
为对象添加弹簧动画效果要制作弹簧动画,您需要
创建 SpringAnimation
的实例
类并提供一个对象、一个要添加动画效果的对象属性,以及
(可选)您希望动画停放的最终弹簧位置。
注意:在创建弹簧动画时, 弹簧的位置是可选的不过,您必须定义 然后再开始播放动画
Kotlin
val springAnim = findViewById<View>(R.id.imageView).let { img -> // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f) }
Java
final View img = findViewById(R.id.imageView); // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);
基于弹簧的动画可通过更改 实际属性以下视图适用于 系统:
ALPHA
: 表示视图的 Alpha 透明度。值为 1(不透明)乘以 默认值,值为 0 表示完全透明(不可见)。TRANSLATION_X
,TRANSLATION_Y
和TRANSLATION_Z
:这些 属性控制视图的位置,以相对于其左侧的增量值表示 坐标、顶部坐标和高度,由布局设置 容器。TRANSLATION_X
描述左侧坐标。TRANSLATION_Y
描述最高坐标。TRANSLATION_Z
表示视图相对于其高度的深度。
ROTATION
,ROTATION_X
和ROTATION_Y
:这些 属性控制 2D 的旋转(rotation
属性),而 围绕轴心点的 3D 模型。SCROLL_X
和SCROLL_Y
:这些 属性表示来源左侧和顶部边缘的滚动偏移量 (以像素为单位)。它还表示排名 。SCALE_X
和SCALE_Y
:这些 属性用于控制视图围绕其轴心点的 2D 缩放。X
,Y
和Z
:这些是基本 实用程序属性,用于描述视图在其 容器。X
是以下项的总和: 左边的值和TRANSLATION_X
。Y
是以下项的总和: Top-value 和TRANSLATION_Y
。Z
是以下项的总和: 高度值和TRANSLATION_Z
。
注册监听器
DynamicAnimation
类提供两个
监听器数:OnAnimationUpdateListener
和 OnAnimationEndListener
。
这些监听器会监听动画中的更新,例如,当
更改动画值以及动画何时结束。
OnAnimationUpdateListener
如果要为多个视图添加动画效果以创建链式动画,
可以设置OnAnimationUpdateListener
在当前视图的视图每次发生更改时接收回调
属性。回调会通知另一个视图更新其弹簧位置
基于当前数据视图媒体资源中发生的变化进行调整。要注册
因此,请执行以下步骤:
-
调用
addUpdateListener()
方法,并将监听器附加到动画。注意:您需要注册该更新 监听器。不过,更新监听器 只有在需要逐帧更新动画值时才注册 更改。更新监听器可防止动画 在单独的线程上运行
-
替换
onAnimationUpdate()
方法将当前对象的更改告知调用方。通过 以下示例代码说明了OnAnimationUpdateListener
。
Kotlin
// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 -> SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y) } val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 -> SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y) } // Registering the update listener anim1X.addUpdateListener { _, value, _ -> // Overriding the method to notify view2 about the change in the view1’s property. anim2X.animateToFinalPosition(value) } anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }
Java
// Creating two views to demonstrate the registration of the update listener. final View view1 = findViewById(R.id.view1); final View view2 = findViewById(R.id.view2); // Setting up a spring animation to animate the view1 and view2 translationX and translationY properties final SpringAnimation anim1X = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim1Y = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y); final SpringAnimation anim2X = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim2Y = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y); // Registering the update listener anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { // Overriding the method to notify view2 about the change in the view1’s property. @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2X.animateToFinalPosition(value); } }); anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2Y.animateToFinalPosition(value); } });
OnAnimationEndListener
OnAnimationEndListener
通知动画结束。您可以将监听器设置为
回调。接收者
注册监听器,请执行以下步骤:
-
调用
addEndListener()
方法,并将监听器附加到动画。 -
替换
onAnimationEnd()
方法在动画达到平衡时接收通知 或已被取消
移除监听器
要停止接收动画更新回调和动画结束回调,请执行以下操作:
打电话给removeUpdateListener()
和removeEndListener()
方法。
设置动画起始值
要设置动画的起始值,请调用
setStartValue()
方法并传递动画的起始值。如果您没有将
起始值,则动画会使用对象属性的当前值
作为起始值。
设置动画值的范围
您可以根据需要设置动画的最小值和最大值 将属性值限制在特定范围内。它还有助于控制 范围(如果您为具有内在范围的属性添加动画效果,例如 alpha (从 0 到 1)。
-
要设置最小值,请调用
setMinValue()
方法并传递属性的最小值。 -
如需设置最大值,请调用
setMaxValue()
方法,并传递属性的最大值。
这两种方法都能返回正在为其设置值的动画。
注意:如果您已设置起始值,并且 定义了一个动画值范围,请确保起始值在 最小值和最大值。
设置起始速度
起始速度定义了动画属性在 动画的开头。默认起始速度设置为零 像素/秒。您可以通过触摸速度设置速度 或使用一个固定值作为起始速度。如果您选择 提供一个固定值,我们建议以“dp/秒”为单位定义该值, 然后将其转换为每秒像素数。定义“dp/秒”的值 使速度与密度和外形规格无关。有关 有关如何将值转换为每秒像素数的信息,请参阅 将“dp/秒”转换为“像素/秒” 部分。
要设置速度,请调用
setStartVelocity()
方法,并传递以“像素/秒”为单位的速度。该方法会返回
用于设置速度的弹簧弹力对象。
注意:请使用
GestureDetector.OnGestureListener
或
用于检索和计算的 VelocityTracker
类方法
触摸手势的速度
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000) val velocity = vt.yVelocity setStartVelocity(velocity) } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000); float velocity = vt.getYVelocity(); anim.setStartVelocity(velocity);
将“dp/秒”转换为“像素/秒”
弹簧的速度必须以“像素/秒”为单位。如果您选择提供
固定值作为速度起始值,请提供以“dp/秒”为单位的值
然后将其转换成“像素/秒”对于转化指标,请使用
applyDimension()
方法中 TypedValue
类。请参阅
以下示例代码:
Kotlin
val pixelPerSecond: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)
Java
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());
设置弹簧属性
SpringForce
类定义了 getter
以及每个弹簧属性(例如阻尼)的 setter 方法
调整比和刚度要设置弹簧属性,必须
检索弹簧弹力对象,或创建一个自定义弹簧弹力,
您可以设置属性如需详细了解如何创建自定义
弹簧弹力,请参阅
创建自定义弹簧弹力
部分。
提示:使用 setter 方法时,您可以 创建一个方法链,因为所有的 setter 方法都会返回弹簧弹力 对象。
阻尼比
阻尼比用于描述弹簧振动逐渐衰减的状况。修改者 您可以确定振幅衰减的速度有多快 您可以通过四种不同的方法 春季:
- 当阻尼比大于 1 时,会出现过阻尼现象。它让 让物体轻轻地回到静止位置。
- 当阻尼比等于 1 时,会出现临界阻尼现象。它让 使对象在最短时间内返回到静止位置。
- 当阻尼比小于 1 时,会出现欠阻尼现象。它让 会多次传递物体的静止位置, 会逐渐到达静止位置
- 当阻尼比等于零时,便会出现无阻尼现象。它让 物体将永远振动。
如需为弹簧添加阻尼比,请执行以下步骤:
-
调用
getSpring()
方法检索弹簧以添加阻尼比。 -
调用
setDampingRatio()
方法,并传递要增加到弹簧上的阻尼比。通过 方法会返回设置了阻尼比的弹簧弹力对象。注意:阻尼比必须为 非负数。如果您将阻尼比设置为零,弹簧将 永远不会到达静止位置也就是说,它会永远振动下去。
系统中提供了以下阻尼比常量:
DAMPING_RATIO_HIGH_BOUNCY
DAMPING_RATIO_MEDIUM_BOUNCY
DAMPING_RATIO_LOW_BOUNCY
DAMPING_RATIO_NO_BOUNCY
图 2:高弹力
图 3:中弹跳
图 4:低弹跳
图 5:无弹跳
默认阻尼比设置为 DAMPING_RATIO_MEDIUM_BOUNCY
。
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the damping ratio to create a low bouncing effect. spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the damping ratio to create a low bouncing effect. anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY); …
刚度
刚度定义了弹簧常数,该常数用于测量 春天。刚性弹簧可对所连接物体施加更大的力 当弹簧未处于静止位置时 如需增加弹簧的刚度,请执行以下步骤:
-
调用
getSpring()
方法来检索弹簧以增加刚度。 -
调用
setStiffness()
方法,并传递要添加到弹簧的刚度值。通过 方法会返回设置了刚度的弹簧弹力对象。注意:刚度必须为 正数。
系统中提供了以下刚度常数:
图 6:高刚度
图 7:中刚度
图 8:低刚度
图 9:非常低的刚度
默认刚度设置为 STIFFNESS_MEDIUM
。
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the spring with a low stiffness. spring.stiffness = SpringForce.STIFFNESS_LOW … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the spring with a low stiffness. anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW); …
创建自定义弹簧弹力
您可以创建自定义弹簧弹力,作为使用默认弹簧弹力的替代方法 弹簧弹力自定义弹簧弹力可让您共用相同的弹簧弹力, 多个弹簧动画实例。创建 力,可以设置阻尼比和刚度等属性。
-
创建一个
SpringForce
对象。SpringForce force = new SpringForce();
-
通过调用相应的方法来分配属性。您还可以
创建方法链
force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW);
-
调用
setSpring()
方法为动画设置弹簧。setSpring(force);
启动动画
启动弹簧动画的方法有两种:调用
start()
或通过调用
animateToFinalPosition()
方法。这两种方法都需要在主线程上调用。
animateToFinalPosition()
方法会执行两项任务:
- 设置弹簧的最终位置。
- 启动动画(如果尚未启动)。
由于此方法会更新弹簧的最终位置,
如果需要,您可以随时调用此方法,以便更改
动画效果例如,在链接的弹簧动画中,动画
一个视图依赖于另一个视图。对于这种动画来说
使用
animateToFinalPosition()
方法。通过在链接的弹簧动画中使用此方法,您不需要
以防您接下来要更新的动画目前正在运行。
图 10 展示了一个链接的弹簧动画,其中其中一个动画 视图依赖于另一个视图。
<ph type="x-smartling-placeholder">![链接的弹簧动画演示](https://developer.android.google.cn/static/images/guide/topics/graphics/spring_chain.gif?authuser=7&hl=sk)
要使用 animateToFinalPosition()
方法,调用
animateToFinalPosition()
方法,并传递弹簧的静止位置。您还可以使用
通过调用
setFinalPosition()
方法。
start()
方法
不要立即将属性值设置为起始值。属性
值会随着每个动画脉冲而发生变化,这发生在绘制传递之前。
因此,这些更改会反映在下一帧中,就好像
这些值会立即设置
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Starting the animation start() … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Starting the animation anim.start(); …
取消动画
您可以取消动画或跳至动画结尾处。理想情况 需要取消或跳到动画结尾的情况是 会要求立即终止动画。这是 通常在用户突然退出应用或视图变得不可见时。
您可以使用两种方法来终止动画。
cancel()
方法
在动画所在的位置终止动画。通过
skipToEnd()
方法
将动画跳过到最终值,然后终止它。
在终止动画之前,请务必先查看
弹簧的状态如果状态为无阻尼,则动画永远不会到达
静止不动
要查看弹簧的状态,请调用
canSkipToEnd()
方法结合使用。如果
表示弹簧处于阻尼状态,该方法会返回 true
,否则
false
。
知道弹簧的状态后,您可以通过以下方法终止动画:
使用
skipToEnd()
方法或
cancel()
方法。通过
cancel()
种方式
必须仅在主线程上调用。
注意:通常情况下,
skipToEnd()
方法的成因