属性动画系统是一个稳健的框架, 为几乎任何事物添加动画效果。您可以定义一个动画,以便随时间更改任何对象属性, 而不管它是否会在屏幕上绘制属性动画会更改属性的 (对象中的字段)值。要为某对象添加动画效果,您可以指定 要添加动画效果的对象属性,例如对象在屏幕上的位置、 您希望为其添加动画效果,以及要在哪些值之间添加动画效果。
通过属性动画系统,您可以定义 动画:
- 时长:您可以指定动画的时长。默认时长为 300 毫秒。
- 时间插值:您可以指定如何以 函数。
- 重复计数和行为:您可以指定在发生以下情况时是否重复播放动画: 播放动画。您还可以 指定是否要反向播放动画。将其设置为反向播放 动画先快进再反复播放,直到达到重复次数。
- Animator 集:您可以将动画分组到一起播放或 或在指定延迟时间之后。
- 帧刷新延迟:您可以指定动画帧的刷新频率。通过 默认设置为每 10 毫秒刷新一次,但应用的帧刷新速度为 最终取决于系统的整体繁忙程度以及系统为底层计时器提供服务的速度。
如需查看属性动画的完整示例,请参阅
CustomTransition 中的 ChangeColor
类
示例。
属性动画的工作原理
首先,让我们通过一个简单的示例来了解动画的工作原理。图 1 描绘了
使用 x
属性添加动画效果的假设对象,该属性表示其
在屏幕上的水平位置。动画时长设置为 40 毫秒,距离
移动距离为 40 像素此对象每 10 毫秒(这是默认的帧刷新频率)移动一次
横向移动 10 像素在 40 毫秒结束时,动画停止,并且对象在
水平位置 40。这是一个使用线性插值的动画示例,表示
物体以恒速移动的物体
![](https://developer.android.google.cn/static/images/animation/animation-linear.png?authuser=8&hl=ro)
图 1. 线性动画示例
您也可以指定动画使用非线性插值。图 2 显示了 在动画开始时加速并在 动画结束。该对象仍在 40 毫秒内移动了 40 像素,但这种移动是非线性的。在 一开始,这个动画会加速到一半,然后再减速至一半, 距离动画结尾过半。如图 2 所示,用户经过的距离 动画开头和结尾的值小于中间值。
![](https://developer.android.google.cn/static/images/animation/animation-nonlinear.png?authuser=8&hl=ro)
图 2. 非线性动画示例
我们来详细了解一下属性动画系统的重要组件是如何 会计算如上图所示的动画。图 3 说明了主类 相互协作。
![](https://developer.android.google.cn/static/images/animation/valueanimator.png?authuser=8&hl=ro)
图 3. 如何计算动画
ValueAnimator
对象会跟踪动画的时间设置,
例如动画已运行了多长时间,以及它所具有的属性的当前值。
动画效果
ValueAnimator
封装了 TimeInterpolator
(用于定义动画插值)和 TypeEvaluator
(用于定义如何计算所具有的属性的值)
动画效果。例如,在图 2 中,所使用的 TimeInterpolator
为
AccelerateDecelerateInterpolator
,TypeEvaluator
为 IntEvaluator
。
如需启动动画,请创建一个 ValueAnimator
并为其指定
要添加动画效果的属性的起始值和结束值,以及
动画。当您调用 start()
时,系统会
。在整个动画播放期间,ValueAnimator
会计算已用分数
介于 0 和 1 之间,具体取决于动画的时长和已过去的时间。通过
已播放分数表示动画已完成时间的百分比,0 表示 0%
1 表示 100%。例如,在图 1 中,t = 10 毫秒时经过的分数为 0 .25
因为总时长为 t = 40 毫秒。
ValueAnimator
计算出已完成动画分数后,
会调用当前设置的 TimeInterpolator
,以计算
插值分数。插值分数会将已完成分数映射到新的分数
将所设置的时间插值考虑在内的比例。例如,在图 2 中,
由于动画缓慢加速,因此插值分数(约 0 .15)会小于
已用分数 (0.25),t = 10 毫秒。在图 1 中,插值分数始终与
已完成的部分。
计算插值分数时,ValueAnimator
会调用
相应的 TypeEvaluator
,以计算
您要为之添加动画效果的属性,该元素根据插值分数、起始值和
动画的结束值。例如,在图 2 中,t = 时的插值分数为 0 .15。
10 ms,因此该属性的值将是 0.15 × (40 - 0) 或 6。
属性动画与视图动画的区别
视图动画系统提供仅为 View
添加动画效果的功能
因此,如果您想为非 View
对象添加动画效果,则必须实现
编写自己的代码视图动画系统也受到了限制,因为
公开了要添加动画效果的 View
对象的多个方面,例如缩放和
旋转视图,但不改变背景颜色。
视图动画系统的另一个缺点是,它只有在 视图是绘制的,而不是实际的视图本身。例如,如果您为某个按钮移动 在屏幕上,按钮可以正确绘制,但是可以点击按钮的实际位置 按钮不会发生变化,因此您必须实现自己的逻辑来处理这种情况。
借助属性动画系统,这些约束条件会被完全消除,并且您可以为 任何对象(View 和非 View)的任何属性,并且对象本身实际上已经过修改。 属性动画系统在执行动画方面也更为强健。在 大体上讲,您可以为要添加动画效果的属性分配动画程序,例如颜色、 位置或大小,并可以定义动画的各个方面,例如插值和 同步多个 Animator。
不过,视图动画系统的设置时间较短,需要编写的代码也较少。 如果视图动画完成了您需要执行的所有操作,或者您的现有代码已经完成, 因此无需使用属性动画系统。它也可能会 如果出现使用情形,可以针对不同情况同时使用这两种动画系统。
API 概览
您可以在 android.animation
中找到属性动画系统的大多数 API。由于视图动画系统已经
在 android.view.animation
中定义了许多插值器,您可以使用
以及属性动画系统中的插值器。下表介绍了
属性动画系统的组件。
Animator
类提供了用于创建
动画。您通常不会直接使用以下类,因为它只提供
功能。以下
子类扩展 Animator
:
表 1. Animator
类 | 说明 |
---|---|
ValueAnimator |
属性动画的主计时引擎,也会为
属性。它包含计算动画的所有核心功能
值,并包含每个动画的时间详情、有关
动画重复次数、接收更新事件的监听器、设置自定义
要评估的类型。为属性添加动画效果分为两部分:计算动画效果
值并在动画对象和属性上设置这些值。ValueAnimator 不执行第二部分,所以您必须听
用于更新由 ValueAnimator 和
使用您自己的逻辑修改要添加动画效果的对象。请参阅
如需了解详情,请使用 ValueAnimator 添加动画效果。 |
ObjectAnimator |
ValueAnimator 的子类,允许您设置目标
对象和对象属性来添加动画效果。当发生以下情况时,该类会相应地更新属性:
将为动画计算一个新值。您想使用
ObjectAnimator 大多数时候,
因为它可以大大简化为目标对象上的值添加动画效果的过程。不过,
有时,您需要直接使用 ValueAnimator ,因为 ObjectAnimator 还有其他一些限制,例如要求
访问器方法。 |
AnimatorSet |
提供一种将动画分组到一起的机制, 相互关系。您可以将动画设置为一起播放、依序播放或播放后播放 指定延迟时间。请参阅编排多个 动画和动画。 |
评估器会告知属性动画系统如何计算指定值
属性。它们会获取 Animator
提供的时间数据
类设置动画的起始值和结束值,并计算属性的动画值
生成自定义文本。属性动画系统可提供以下评估程序:
表 2. 评估程序
类/接口 | 说明 |
---|---|
IntEvaluator |
这是用于计算 int 属性的值的默认评估程序。 |
FloatEvaluator |
这是用于计算 float 属性的值的默认评估程序。 |
ArgbEvaluator |
用于计算所表示颜色属性的值的默认评估程序 以十六进制值表示。 |
TypeEvaluator |
此接口用于创建您自己的评估程序。如果您要为
不是 int 、float 或 color 的对象属性,
您必须实现 TypeEvaluator 接口,以指定
计算对象属性的动画值。您还可以为 int 、float 和颜色指定自定义 TypeEvaluator
值。
如需了解详情,请参阅使用 TypeEvaluator 部分
了解如何编写自定义评估程序。 |
时间插值器定义了动画中的特定值如何以
时间函数。例如,您可以指定在整个
即“Animation”(即动画在整个播放期间均匀移动),也可以指定动画
使用非线性时间,例如,在开始时加速并在
动画结束。表 3 介绍了 android.view.animation
中包含的插值器。如果提供的插值器都不合适
实现 TimeInterpolator
接口并创建您自己的接口。如需详细了解如何编写自定义规则,请参阅使用插值器
插值器。
表 3. 插值器
类/接口 | 说明 |
---|---|
AccelerateDecelerateInterpolator |
该插值器的变化率在开始和结束时缓慢但加快 |
AccelerateInterpolator |
该插值器的变化率在开始时较为缓慢,然后 加速。 |
AnticipateInterpolator |
该插值器先反向变化,然后再急速正向变化。 |
AnticipateOvershootInterpolator |
该插值器先反向变化,然后再急速正向变化,然后再溢出 目标值,最后返回到最终值。 |
BounceInterpolator |
该插值器的变化会跳过结尾处。 |
CycleInterpolator |
该插值器的动画会在指定数量的周期内重复。 |
DecelerateInterpolator |
该插值器的变化率在开始时很快,然后 减速。 |
LinearInterpolator |
该插值器的变化率恒定不变。 |
OvershootInterpolator |
该插值器的变化会急速正向并超过最终值,然后 。 |
TimeInterpolator |
该接口用于实现您自己的插值器。 |
使用 ValueAnimator 添加动画效果
借助 ValueAnimator
类,您可以为
通过指定一组 int
、float
或 color 来设定动画的时长
添加动画效果您可以通过调用以下方法之一来获取 ValueAnimator
:
其工厂方法:ofInt()
、ofFloat()
或 ofObject()
。例如:
Kotlin
ValueAnimator.ofFloat(0f, 100f).apply { duration = 1000 start() }
Java
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f); animation.setDuration(1000); animation.start();
在此代码中,ValueAnimator
开始计算
0 到 100 之间的动画时长,时长为 1000 毫秒(当 start()
方法运行时)。
您还可以通过执行以下操作来指定要添加动画效果的自定义类型:
Kotlin
ValueAnimator.ofObject(MyTypeEvaluator(), startPropertyValue, endPropertyValue).apply { duration = 1000 start() }
Java
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue); animation.setDuration(1000); animation.start();
在此代码中,ValueAnimator
开始计算
startPropertyValue
和 endPropertyValue
之间使用
当 start()
方法运行时,由 MyTypeEvaluator
提供的 1000 毫秒时长的逻辑。
您可以通过添加
AnimatorUpdateListener
添加到 ValueAnimator
对象,如
以下代码:
Kotlin
ValueAnimator.ofObject(...).apply { ... addUpdateListener { updatedAnimation -> // You can use the animated value in a property that uses the // same type as the animation. In this case, you can use the // float value in the translationX property. textView.translationX = updatedAnimation.animatedValue as Float } ... }
Java
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator updatedAnimation) { // You can use the animated value in a property that uses the // same type as the animation. In this case, you can use the // float value in the translationX property. float animatedValue = (float)updatedAnimation.getAnimatedValue(); textView.setTranslationX(animatedValue); } });
在onAnimationUpdate()
中
方法,您可以访问更新后的动画值,并将其用于
您的某个数据视图有关监听器的详情,请参阅
动画监听器。
使用 ObjectAnimator 添加动画效果
ObjectAnimator
是 ValueAnimator
的子类(上一部分已讨论过),它结合了时间设置
ValueAnimator
的引擎和价值计算,能够
为目标对象的命名属性添加动画效果。这大大简化了为任何对象添加动画效果的过程,
不再需要实现 ValueAnimator.AnimatorUpdateListener
,
因为动画属性会自动更新。
实例化 ObjectAnimator
的操作与 ValueAnimator
类似,但您还需要指定对象以及该对象属性的名称(如
字符串),以及要在其间添加动画效果的值:
Kotlin
ObjectAnimator.ofFloat(textView, "translationX", 100f).apply { duration = 1000 start() }
Java
ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f); animation.setDuration(1000); animation.start();
让 ObjectAnimator
更新属性
您必须执行以下操作:
- 要添加动画效果的对象属性必须具有 setter 函数(采用驼峰式大小写形式),格式为
set<PropertyName>()
。因为ObjectAnimator
在动画播放期间自动更新属性,它必须能够访问该属性 使用此 setter 方法。例如,如果属性名称为foo
,则需要执行以下操作: 具有setFoo()
方法。如果此 setter 方法不存在,您将得到三个 选项: <ph type="x-smartling-placeholder">- </ph>
- 如果您有权限,可将 setter 方法添加到类中。
- 使用您有权更改的封装容器类,并让该封装容器接收 值并将其转发给原始对象。
- 改用
ValueAnimator
。
- 如果您在某个
ObjectAnimator
工厂方法中仅为values...
形参指定一个值,则系统会假定该值是 动画。因此,要添加动画效果的对象属性必须具有 getter 函数 用于获取动画的起始值。getter 函数必须位于 采用get<PropertyName>()
格式。例如,如果属性名称为foo
,您需要一个getFoo()
方法。 - 要添加动画效果的属性的 getter(如果需要)和 setter 方法必须
运算类型与您为
ObjectAnimator
指定的起始值和结束值相同。例如,您必须targetObject.setPropName(float)
和targetObject.getPropName()
如果您构造以下ObjectAnimator
:ObjectAnimator.ofFloat(targetObject, "propName", 1f)
- 根据要添加动画效果的属性或对象,您可能需要对 View 调用
invalidate()
方法,以强制屏幕使用 已更新动画值。您可以在onAnimationUpdate()
回调。例如,为可绘制对象的 color 属性添加动画效果只会导致系统对 重新绘制自身时返回屏幕。View 上的所有属性 setter,例如setAlpha()
和setTranslationX()
适当地使视图失效,因此在调用 方法。有关监听器的详情,请参阅 动画监听器。
使用 AnimatorSet 编排多个动画
在许多情况下,您需要根据另一个动画何时开始播放或
。Android 系统允许您将动画捆绑到 AnimatorSet
中,以便指定是否启动动画
同时、依序或在指定的延迟时间后。您还可以相互嵌套 AnimatorSet
对象。
以下代码段会播放下面的 Animator
对象:
- 播放
bounceAnim
。 - 播放
squashAnim1
、squashAnim2
、stretchAnim1
和stretchAnim2
。 - 播放
bounceBackAnim
。 - 播放
fadeAnim
。
Kotlin
val bouncer = AnimatorSet().apply { play(bounceAnim).before(squashAnim1) play(squashAnim1).with(squashAnim2) play(squashAnim1).with(stretchAnim1) play(squashAnim1).with(stretchAnim2) play(bounceBackAnim).after(stretchAnim2) } val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply { duration = 250 } AnimatorSet().apply { play(bouncer).before(fadeAnim) start() }
Java
AnimatorSet bouncer = new AnimatorSet(); bouncer.play(bounceAnim).before(squashAnim1); bouncer.play(squashAnim1).with(squashAnim2); bouncer.play(squashAnim1).with(stretchAnim1); bouncer.play(squashAnim1).with(stretchAnim2); bouncer.play(bounceBackAnim).after(stretchAnim2); ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); fadeAnim.setDuration(250); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(bouncer).before(fadeAnim); animatorSet.start();
动画监听器
您可以使用下文所述的监听器来监听动画播放期间的重要事件。
Animator.AnimatorListener
onAnimationStart()
- 在动画开始时调用。onAnimationEnd()
- 在动画结束时调用。onAnimationRepeat()
- 在动画重复播放时调用。onAnimationCancel()
- 在动画取消播放时调用。已取消的动画 还会调用onAnimationEnd()
, 无论它们是如何结束的
ValueAnimator.AnimatorUpdateListener
-
onAnimationUpdate()
- 对动画的每一帧调用。收听此事件 使用ValueAnimator
在 动画。如需使用该值,请查询ValueAnimator
对象 并使用getAnimatedValue()
方法获取当前动画值。实现此方法 如果您使用ValueAnimator
,则必须包含监听器。根据您要添加动画效果的属性或对象,您可能需要调用
invalidate()
,用于强制 使用新的动画值重新绘制自身。例如,为 color 属性,仅当该对象 会重新绘制自身View 的所有属性 setter 例如setAlpha()
和setTranslationX()
会使视图失效 因此,在使用新值调用这些方法时,您无需使 View 失效。
-
您可以扩展 AnimatorListenerAdapter
类,而不是
实现 Animator.AnimatorListener
接口(如果没有
希望实现 Animator.AnimatorListener
的所有方法
界面。AnimatorListenerAdapter
类提供空的
您可以选择替换的方法的实现。
例如,以下代码段会创建一个 AnimatorListenerAdapter
仅针对 onAnimationEnd()
回调:
Kotlin
ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply { duration = 250 addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { balls.remove((animation as ObjectAnimator).target) } }) }
Java
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); fadeAnim.setDuration(250); fadeAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { balls.remove(((ObjectAnimator)animation).getTarget()); }
为 ViewGroup 对象的布局更改添加动画效果
属性动画系统提供为 ViewGroup 对象更改添加动画效果的功能 还可以轻松为 View 对象本身添加动画效果。
您可以使用
LayoutTransition
类。ViewGroup 内的视图
这些动画会逐一出现和消失动画
或者当您调用 View 的
setVisibility()
方法与
VISIBLE
、INVISIBLE
或
GONE
。ViewGroup 中的其余 View 也可以
添加或移除 View 时,以动画形式移动到新位置。你可以定义
LayoutTransition
对象中的以下动画
通过调用 setAnimator()
并传入包含其中一个参数的 Animator
对象,
以下 LayoutTransition
常量:
APPEARING
- 该标志表示动画在 容器中显示的内容CHANGE_APPEARING
- 该标志表示动画在 会由于容器中出现新项而发生变化。DISAPPEARING
- 该标志表示动画在 从容器中消失CHANGE_DISAPPEARING
- 该标记表示动画在符合以下条件的项上运行 会因为某个项目从容器中消失而发生变化。
您可以为这四种类型的事件定义自己的自定义动画,以自定义外观 或者直接指示动画系统使用默认动画。
若要将 android:animateLayoutchanges
属性设置为 true
,
ViewGroup 将执行以下操作:
<LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="match_parent" android:id="@+id/verticalContainer" android:animateLayoutChanges="true" />
将此属性设为 true 可自动为添加到此或从中移除的 View 添加动画效果 ViewGroup 以及 ViewGroup 中的其他 View。
使用 StateListAnimator 为视图状态更改添加动画效果
借助 StateListAnimator
类,您可以定义在发生以下情况时运行的动画程序:
视图的状态会发生变化此对象充当
Animator
对象,每当指定
视图状态(例如“按下”或“聚焦”)的变化。
可以使用根目录在 XML 资源中定义 StateListAnimator
<selector>
元素和 <item>
子元素(各自指定)
由 StateListAnimator
类定义的不同视图状态。每个
<item>
包含属性动画集的定义。
例如,以下文件会创建一个状态列表 animator,用于更改 x 和 y 缩放 视图的以下按钮:
res/xml/animate_scale.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- the pressed state; increase x and y size to 150% --> <item android:state_pressed="true"> <set> <objectAnimator android:propertyName="scaleX" android:duration="@android:integer/config_shortAnimTime" android:valueTo="1.5" android:valueType="floatType"/> <objectAnimator android:propertyName="scaleY" android:duration="@android:integer/config_shortAnimTime" android:valueTo="1.5" android:valueType="floatType"/> </set> </item> <!-- the default, non-pressed state; set x and y size to 100% --> <item android:state_pressed="false"> <set> <objectAnimator android:propertyName="scaleX" android:duration="@android:integer/config_shortAnimTime" android:valueTo="1" android:valueType="floatType"/> <objectAnimator android:propertyName="scaleY" android:duration="@android:integer/config_shortAnimTime" android:valueTo="1" android:valueType="floatType"/> </set> </item> </selector>
要将状态列表 Animator 附加到视图,请添加
android:stateListAnimator
属性,如下所示:
<Button android:stateListAnimator="@xml/animate_scale" ... />
现在,当此按钮的状态发生变化时,将使用 animate_scale.xml
中定义的动画
状态更改
或者,如需将状态列表 Animator 分配给代码中的视图,请使用
AnimatorInflater.loadStateListAnimator()
方法,并将 Animator 分配给
使用 View.setStateListAnimator()
方法构建视图。
或者,您不必为视图的属性添加动画效果,而是可以在两个选项之间播放可绘制动画
使用 AnimatedStateListDrawable
更改状态。
其中一些系统小组件
Android 5.0 默认使用这些动画。以下示例展示了如何
将 AnimatedStateListDrawable
定义为 XML 资源:
<!-- res/drawable/myanimstatedrawable.xml --> <animated-selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- provide a different drawable for each state--> <item android:id="@+id/pressed" android:drawable="@drawable/drawableP" android:state_pressed="true"/> <item android:id="@+id/focused" android:drawable="@drawable/drawableF" android:state_focused="true"/> <item android:id="@id/default" android:drawable="@drawable/drawableD"/> <!-- specify a transition --> <transition android:fromId="@+id/default" android:toId="@+id/pressed"> <animation-list> <item android:duration="15" android:drawable="@drawable/dt1"/> <item android:duration="15" android:drawable="@drawable/dt2"/> ... </animation-list> </transition> ... </animated-selector>
使用 TypeEvaluator
如果您要为 Android 系统无法识别的类型添加动画效果,可以自行创建
通过实现 TypeEvaluator
接口来评估评估器。使系统能够
为 int
、float
或颜色,它们是
受 IntEvaluator
、FloatEvaluator
和 ArgbEvaluator
类型支持
评估程序。
在 TypeEvaluator
中只有一种实现方法
接口,即 evaluate()
方法。这样,
您用来在
动画的当前点。FloatEvaluator
类演示了
操作方法:
Kotlin
private class FloatEvaluator : TypeEvaluator<Any> { override fun evaluate(fraction: Float, startValue: Any, endValue: Any): Any { return (startValue as Number).toFloat().let { startFloat -> startFloat + fraction * ((endValue as Number).toFloat() - startFloat) } } }
Java
public class FloatEvaluator implements TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue) { float startFloat = ((Number) startValue).floatValue(); return startFloat + fraction * (((Number) endValue).floatValue() - startFloat); } }
注意:当 ValueAnimator
(或 ObjectAnimator
)运行时,它会计算当前已播放时长的
(介于 0 和 1 之间的值),然后根据
所用的插值器。插值分数是 TypeEvaluator
通过 fraction
参数接收的分数,因此您需要
在计算动画值时无需考虑插值器。
使用插值器
插值器定义了如何根据 。例如,您可以指定在整个动画中以线性方式播放动画, 表示动画在整个播放期间均匀移动,也可以指定要使用的动画 非线性时间,例如在播放开始或结束时使用加速或减速, 动画。
动画系统中的插值器会从 Animator 接收代表
动画的已播放时长。插值器会修改该分数,以便与
动画效果。Android 系统在
android.view.animation package
。如果这些内容都不适合
您可以实现 TimeInterpolator
接口并创建您自己的
。
例如,下面对默认插值器 AccelerateDecelerateInterpolator
和 LinearInterpolator
计算插值分数的方式进行了比较。
LinearInterpolator
对已完成动画分数没有任何影响。AccelerateDecelerateInterpolator
会加速进入动画,然后
从而减速以下方法定义了这些插值器的逻辑:
AccelerateDecelerateInterpolator
Kotlin
override fun getInterpolation(input: Float): Float = (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f
Java
@Override public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; }
LinearInterpolator
Kotlin
override fun getInterpolation(input: Float): Float = input
Java
@Override public float getInterpolation(float input) { return input; }
下表显示了通过上述方法计算得出的近似值 用于时长 1000 毫秒的动画的插值器:
已完成毫秒数 | 已完成动画分数/插值分数(线性) | 插值分数(加速/减速) |
---|---|---|
0 | 0 | 0 |
200 | 0.2 | 0.1 |
400 | 0.4 | 0.345 |
600 | 0.6 | 0.8 |
800 | 0.8 | 0.9 |
1000 | 1 | 1 |
如上表所示,LinearInterpolator
会更改
以相同的速度传递,每传递 200 毫秒返回 0.2。AccelerateDecelerateInterpolator
在 200 毫秒到 600 毫秒之间更改值的速度比 LinearInterpolator
快,在 600 毫秒到 600 毫秒之间变化较慢
1000 毫秒。
指定关键帧
Keyframe
对象由时间/值对组成,允许您定义
动画的特定时间的特定状态每个关键帧也有
插值器来控制前一个插值器之间的动画行为,
该关键帧的时间点以及该关键帧的时间点
如需实例化 Keyframe
对象,您必须使用工厂
方法(ofInt()
、ofFloat()
或 ofObject()
)来获取相应类型的 Keyframe
。然后,您调用
ofKeyframe()
工厂方法
获取 PropertyValuesHolder
对象。获得对象后,您可以
通过传入 PropertyValuesHolder
对象获取 Animator
添加动画效果以下代码段演示了如何做到这一点:
Kotlin
val kf0 = Keyframe.ofFloat(0f, 0f) val kf1 = Keyframe.ofFloat(.5f, 360f) val kf2 = Keyframe.ofFloat(1f, 0f) val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2) ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation).apply { duration = 5000 }
Java
Keyframe kf0 = Keyframe.ofFloat(0f, 0f); Keyframe kf1 = Keyframe.ofFloat(.5f, 360f); Keyframe kf2 = Keyframe.ofFloat(1f, 0f); PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2); ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation); rotationAnim.setDuration(5000);
为视图添加动画效果
属性动画系统支持为视图对象添加简化的动画, 相较于视图动画系统的一些优势。视图 动画系统通过更改视图对象的绘制方式来转换这些对象。这是 会在每个 View 的容器中进行处理,因为 View 本身没有可操控的属性。 这会导致视图在表面上添加了动画效果,但视图对象本身没有任何变化。本次 会导致出现这样的行为,例如,即使某个对象 在屏幕上的其他位置绘制的。在 Android 3.0 中,新属性和对应的 我们添加了 getter 和 setter 方法来消除此缺陷。
属性动画系统
可以通过更改 View 对象中的实际属性为屏幕上的 View 添加动画效果。在
此外,View 还会自动调用 invalidate()
方法,以便在其属性发生更改时刷新屏幕。View
类中有利于属性动画的新属性包括:
translationX
和translationY
:这些属性用于控制 视图位于其左侧和顶部坐标的增量内,后者由其布局设置 容器。rotation
、rotationX
和rotationY
:这些属性 控制围绕轴心点的 2D(rotation
属性)和 3D 旋转。scaleX
和scaleY
:这些属性用于控制 围绕其轴心点的视图。pivotX
和pivotY
:这些属性用于控制 旋转和缩放转换围绕的轴心点。默认情况下,数据透视 点位于对象的中心。x
和y
:这些是简单的实用程序属性,用于描述 View 在容器中的最终位置,即左侧值和顶部值与 TranslationX 和 translationY 值。alpha
:表示视图的 Alpha 透明度。此值为 1(不透明) 值为 0 表示完全透明(不可见)。
要为 View 对象的属性(例如其颜色或旋转值)添加动画效果,只需 方法是创建一个属性动画程序,并指定要 设置动画效果。例如:
Kotlin
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)
Java
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
如需详细了解如何创建动画,请参阅有关使用 ValueAnimator 和 ObjectAnimator。
使用 ViewPropertyAnimator 添加动画效果
ViewPropertyAnimator
提供了一种简单的方法来为多个
View
属性并行使用单个底层Animator
对象。它的行为与 ObjectAnimator
非常相似,因为它会修改
使用视图属性的实际值,但在为多个属性添加动画效果时,
一次。此外,使用 ViewPropertyAnimator
的代码是
更简洁、更易读。以下代码段显示了使用
ObjectAnimator
对象,单个
ObjectAnimator
,且ViewPropertyAnimator
同时为视图的 x
和 y
属性添加动画效果。
多个 ObjectAnimator 对象
Kotlin
val animX = ObjectAnimator.ofFloat(myView, "x", 50f) val animY = ObjectAnimator.ofFloat(myView, "y", 100f) AnimatorSet().apply { playTogether(animX, animY) start() }
Java
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f); ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f); AnimatorSet animSetXY = new AnimatorSet(); animSetXY.playTogether(animX, animY); animSetXY.start();
一个 ObjectAnimator
Kotlin
val pvhX = PropertyValuesHolder.ofFloat("x", 50f) val pvhY = PropertyValuesHolder.ofFloat("y", 100f) ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start()
Java
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f); PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f); ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();
ViewPropertyAnimator
Kotlin
myView.animate().x(50f).y(100f)
Java
myView.animate().x(50f).y(100f);
如需详细了解 ViewPropertyAnimator
,请参阅相应的 Android 开发者
博客
发布。
在 XML 中声明动画
通过属性动画系统,您可以使用 XML 来声明属性动画, 以编程方式创建通过在 XML 中定义动画,你可以轻松地重复使用动画 并且可以更轻松地修改动画序列。
为了区分使用新的属性动画 API 的动画文件与使用
旧版视图动画框架
从 Android 3.1 开始,您应将属性动画的 XML 文件保存在 res/animator/
目录中。
以下属性动画类支持带有 以下 XML 标记:
ValueAnimator
-<animator>
ObjectAnimator
-<objectAnimator>
AnimatorSet
-<set>
要查找可在 XML 声明中使用的属性,请参见动画 资源。以下示例会播放两组对象动画 第一个嵌套组依序播放两个对象动画:
<set android:ordering="sequentially"> <set> <objectAnimator android:propertyName="x" android:duration="500" android:valueTo="400" android:valueType="intType"/> <objectAnimator android:propertyName="y" android:duration="500" android:valueTo="300" android:valueType="intType"/> </set> <objectAnimator android:propertyName="alpha" android:duration="500" android:valueTo="1f"/> </set>
为了运行此动画,您必须将代码中的 XML 资源扩充为 AnimatorSet
对象,然后在开始运行动画集之前为所有动画设置目标对象。为方便起见,调用 setTarget()
即可设置一个用于 AnimatorSet
的所有子项的目标对象。以下代码展示了如何执行此操作:
Kotlin
(AnimatorInflater.loadAnimator(myContext, R.animator.property_animator) as AnimatorSet).apply { setTarget(myObject) start() }
Java
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.animator.property_animator); set.setTarget(myObject); set.start();
您还可以在 XML 中声明 ValueAnimator
,如下所示:
如以下示例中所示:
<animator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:valueType="floatType" android:valueFrom="0f" android:valueTo="-100f" />
如需在代码中使用前面的 ValueAnimator
,您需要
必须扩充该对象,添加一个
AnimatorUpdateListener
,
获取更新后的动画值,并将其用于某个视图的属性,
如以下代码所示:
Kotlin
(AnimatorInflater.loadAnimator(this, R.animator.animator) as ValueAnimator).apply { addUpdateListener { updatedAnimation -> textView.translationX = updatedAnimation.animatedValue as Float } start() }
Java
ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animator); xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator updatedAnimation) { float animatedValue = (float)updatedAnimation.getAnimatedValue(); textView.setTranslationX(animatedValue); } }); xmlAnimator.start();
有关定义属性动画的 XML 语法的信息,请参见动画 资源 。
对界面性能的潜在影响
更新界面的 Animator 会导致 动画的运行时间因此,使用资源密集型动画 可能会对应用的性能产生负面影响。
动画界面所需的工作已添加到动画阶段 渲染管道的过程您可以查看动画是否会影响 通过启用 GPU 渲染模式分析和 监控动画阶段。如需了解详情,请参阅 GPU 渲染模式分析 演示。