安卓开发指南翻译:属性动画,Property Animation
属性动画系统,是一个稳健的框架,使得妳能够对几乎任何东西应用动画。妳可以定义一个动画,用来让任何对象的属性随着时间改变,而无论该对象是否被绘制到屏幕上了。属性动画,能够在指定的时间段内改变某个属性(某个对象中的某个字段)的值。为了以动画展现某个东西,妳需要指定:想要让其以动画形式展现的对象属性,例如某个对象在屏幕上的位置;妳希望动画持续多长时间;以及,动画的起始值和终止值是什么。
属性动画系统,使得妳能够定义某个动画的以下特性:
•.持续时间:可指定动画的持续时间。默认长度是300毫秒。
•.时间插值方式:可以指定,属性的值与动画的逝去时间之间是什么样的函数关系。
•.重复次数及行为:妳可以指定,当某个动画到达其一遍的结尾的时候,是否要重复,以及,重复多少次。还可以指定,是否希望该动画反向播放。将它设置为反向播放的话,则,在重复的过程中会以正向和反向交替进行,直到达到重复次数为止。
•.动画集合:妳可以将多个动画组合成逻辑集合,让它们一起运行,或者依次运行,或者在经过特定延迟之后运行。
•. 帧刷新延迟:妳可以指定,以什么频率来刷新妳的动画中的帧。默认值是每隔10毫秒刷新一次,但是,妳的应用程序能够刷新帧的速度,最终是由以下两点决定的:系统整体上有多少繁忙;以及,系 统可以以多快的速度为底层时钟提供服务。
首先 ,让我们以一个简单的示例来研究动画 的工作方式。 图 1展示 的是, 一个假想的对象,它的 x 属性(代表 着它在屏幕上的水平位置 )参与了动画过程。动画 的持续时间设置为 40毫秒,移动距离 是 40像素 。按照默认 的帧刷新率,每隔 10毫秒, 该对象会在水平方向上移动 10像素 。 在 40毫秒 的终止时刻,动画停止 , 而该对象, 也会停止在水平方向上 40像素 的位置。 这个示例中,动画是线性插值的,即, 该对象以匀速移动。
图 1. 线性动画示例
妳还可以指定让动画拥有非线性插值。图2展示了,一个假想的对象,它在动画的开始部分加速,在动画的结束部分减速。这个对象仍然会在40 毫秒中移动40 像素,但是并非是线性地移动。在一开始,动画过程会加速到达中间点,然后减速到达最终点。如图2所示,在开头和结尾阶段移动的距离比中间阶段移动的距离小。
图 2. 非线性动画示例
让我们来详细观摩一下,属性动画系统中的那些重要组件,是如何针对以上所展示的动画进行计算的。图3展示了那些主要类之间的关系。
图 3. 动画 的计算过程
ValueAnimator 对象跟踪着该动画的时间信息(例如, 该动画已经运行了多长时间 ),以及正在 发生动画的那个属性的当前值。
ValueAnimator 内部封装 了一个 TimeInterpolator ( 它定义的是动画过程中的插值 )和一个 TypeEvaluator ( 它定义的是,如何针对正在发生动画的属性计算其值 )。例如 ,在图 2 中, 所使用的 TimeInterpolator 即是 AccelerateDecelerateInterpolator ,而所使用的 TypeEvaluator 即是 IntEvaluator 。
要启动一个动画,则,创建一个 ValueAnimator ,然后,设置以下信息: 要进行动画的那个属性的起始值和终止值; 和,动画的持续时间。 当妳调用 start() 的时候,动画就开始了。 在整个动画过程中, ValueAnimator 会计算出位于0和1之间的一个 逝去比例 值,其计算是以动画的持续时间和逝去时间为依据的。逝去比例 值,代表着, 该动画已经完成的百分比, 0表示0% ,而 1表示100% 。例如, 在图 1 中, 在 t = 10毫秒时刻的逝去比例值是.25,因为 ,整个持续时间是 t = 40毫秒 。
当 ValueAnimator 计算出了逝去比例值之后, 会调用当前设置的 TimeInterpolator ,由该对象来计算出一个 插值比例 值 。插值比例 值,即为, 将逝去比例值映射到一个新的比例值上,在映射过程中会将 已设置的 插值函数计算在内。例如 , 在图 2 中,因为 该动画是缓慢启动的,所以 , 在t = 10 毫秒时刻,插值比例 值,约为.15,是小于逝去比例值.25 的 。 而在图 1 中,插值比例 值是永远与逝去比例值相等的。
计算 出了插值比例值之后, ValueAnimator 会调用适当的 TypeEvaluator , 以计算出当前正在进行动画 的那个属性的值,计算过程 中是以以下数据作为依据的:插值比例 值;动画 的 起始 值;动画的终止值。例如, 在图 2 中,在 t = 10毫秒时刻,插值比例值是.15 ,因此, 在那个时刻,属性 的值是.15 X (40 - 0) , 也就是 6。
应用编程接口演示 示例项目 中的 com.example.android.apis.animation 包,提供了狠多关于如何使用属性动画系统的示例。
视图动画系统 , 只 提供了对 View 对象进行动画的功能,因此,如果 妳想对非 View 对象进行动画,则,需要自己实现相应的代码。 同时, 视图动画系统 ,还有着它自身的限制, 它只暴露 出了 View 对象的少数属性 以用于动画,例如 缩放 、旋转, 而像背景颜色这样的属性,却未提供动画支持。
视图动画系统的另一个缺点就是,它只是修改了该View 被绘制的位置,而未曾修改该View 本身。例如,假设妳对某个按钮启动动画效果,让它从屏幕上飞过,那么,该按钮会正确地绘制出这样的效果,但是,实际可供妳点击该按钮的那个位置,却未曾改变,因此,妳需要自行实现代码来处理这个情况。
使用属性动画系统的时候,这些限制都被解除了,妳可以对任意对象(View和非View)的任意属性进行动画,并且该对象本身是切实被改变了。属性动画系统,在驱动动画的过程中也更加稳健。在一个较高的级别上,妳向妳希望展现出动画的那些属性(例如颜色、位置或尺寸)赋予动画器(animators),并且定义该动画的相关属性,例如插值以及多个动画器之间的同步关系。
然而,另一方面,视图动画系统,设置起来更快,所需编写的代码更少。如果视图动画已经能够完全支持妳所需要实现的功能,或者,妳的已有代码已经狠好地工作着了,那么,妳就不需要使用属性动画系统了。另外,根据实际情况来判断,可能会需要同时使用这两种动画系统。
妳可以在 android.animation 中找到属性动画系统的大部分应用编程接口。由于视图动画系统已经 在 android.view.animation 中定义了狠多插值器,所以 ,妳也可以在属性动画系统中使用这些插值器。 下表说明了属性动画系统的主要组件。
Animator 类,提供了用于创建动画的基本结构。 一般情况下,妳并不直接使用这个类,因为, 它只提供了最小 化 的功能,必须 经过扩展才能完全地支持对值进行动画。以下 子 类,扩展了 Animator :
表 1. 动画 器
类 |
说明 |
属性动画系统中的主要时序引擎,它也会为对之进行动画的属性计算其值。它具有用来计算动画值的所有核心功能,以及:每个动画的时序细节;关于某个动画是否重复的信息;接收更新事件的监听器;以及,设置那些要计算其值的自定义定义的能力。在对属性进行动画的过程中有两件事:计算出动画值;以及,将对应的值设置给要对其进行动画的那个对象的对应属性。 ValueAnimator 并不处理第二点,因此,妳必须监听 ValueAnimator 计算出来的那些值的变化,并且,使用妳自己的逻辑来对那些要进行动画的对象设置其值。参考 利用 ValueAnimator 来实现动画 小节,以了解更多细节。 |
|
ValueAnimator 的一个子类,使得妳能够设置要对其进行动画的目标对象及对象属性。这个类,在为动画过程计算出一个新的值的时候,会对应地更新目标属性的值。大部分情况下,妳应当使用 ObjectAnimator ,因为,它使得对目标对象的值的动画过程变得容易得多。然而,某些情况下,妳需要直接使用 ValueAnimator ,因为, ObjectAnimator 具有某些限制,例如,要求在目标对象中存在特定的访问方法。 |
|
提供一种将多个动画组合起来的机制,使得它们之间能够按照一定的关系来运行。妳可以将多个动画设置为一起运行、串行运行或者经过特定的延迟之后运行。参考 利用动画 器分组来对多个动画进行计划 小节以了解更多信息。 |
算值器(Evaluators),告知属性动画系统要如何计算指定属性 的值。它们需要获取 到由某个 Animator 类提供的时序数据、该动画的起始及终止值,然后,根据 这些数据来计算出该属性的动画值。属性动画系统提供 了以下算值器:
表 2. 算值器
类/接口 |
说明 |
默认的用来针对 int 属性计算其值的算值器。 |
|
默认的用来针对 float 属性计算其值的算值器。 |
|
用来针对以十六进制形式表示的颜色属性计算其值的默认算值器。 |
|
这个接口,允许妳创建自己的算值器。如果妳要对其进行动画的那个对象属性 并不是 int 、 float 或颜色,那么,妳必须实现 TypeEvaluator 接口,以指定,如何计算该对象属性的动画值。另外,对于 int 、 float 和颜色值,如果妳想按照与默认行为所不同的方式来处理那些类型的话,妳同样可以为它们指定一个自定义的 TypeEvaluator 。参考 使用 一个 TypeEvaluator 小节,以了解,如何编写一个自定义的算值器。 |
时序插值 器,定义的是,动画过程 中的某个值,要以怎么样的一个关于时间的函数来计算。例如 , 妳可以指定让动画 在整个过程中以线性方式来进行,也就是说,动画 在整个过程中都是匀速发展的 。或者 , 也可以指定让动画以非线性的时间来进行,例如 , 在开头阶段加速 , 在结束阶段减速。 表 3列出 了 android.view.animation 中包含的那些插值器。如果 这些插值器都不能满足妳的需求,那么,请实现 TimeInterpolator 接口,以创建妳自己的插值器。参考 使用插值 器 以了解更多关于编写自定义插值器的信息。
表 3. 插值 器
类/接口 |
说明 |
这个插值器,在开始阶段和结束阶段的速率缓慢变化,而在中间阶段加速。 |
|
这个插值器,开始阶段的速率缓慢变化,之后加速。 |
|
这个插值器,它先向后变化,然后快速向前。 |
|
这个插值器,它先向事变化,然后快速向前,然后超出目标值,然后回到最终值。 |
|
这个插值器,会在结束阶段产生弹跳效果。 |
|
这个插值器,其动画效果会重复运行指定次数。 |
|
这个插值器,其速率在开始阶段狠快,然后减速。 |
|
这个插值器,其速率恒定。 |
|
这个插值器,首先快速向前,并且越过目标值,然后回到目标值。 |
|
这个接口,允许妳实现自己的插值器。 |
ValueAnimator 类,使得 妳 在动画的持续时间里对某种类型的值进行动画,具体做法就是指定一组要进行动画的 int 、 float 或颜色 值。 妳通过调用某个工厂方法来获取一个 ValueAnimator : ofInt() 、 ofFloat() 或 ofObject() 。例如:
ValueAnimator animation = ValueAnimator . ofFloat ( 0f , 1f );
animation . setDuration ( 1000 );
animation . start ();
在这砣代码中,当 start() 方法开始执行的时候,该 ValueAnimator 就会开始计算 该动画的值: 其值范围是0到1,持续时间是1000 毫秒。
妳也可以通过以下代码来指定对一个自定义类型进行动画:
ValueAnimator animation = ValueAnimator . ofObject ( new MyTypeEvaluator (), startPropertyValue , endPropertyValue );
animation . setDuration ( 1000 );
animation . start ();
在这砣代码中,当 start() 方法开始执行的时候, 该 ValueAnimator 就会开始计算动画的值: 其值范围是 startPropertyValue 到 endPropertyValue ,持续时间是1000 毫秒,并且使用 MyTypeEvaluator 的逻辑来计算。
然而 , 前面 这两砣代码,都不会对任何对象产生任何效果,因为 , ValueAnimator 并不直接操作对象及属性。 妳最想做的事情就是,利用 这些计算出来的值来修改 要对之进行动画的对象。具体做法 就是,定义出将要置于 ValueAnimator 之中的监听器, 以正确地处理该动画的生命周期中的重要事件,例如动画帧的更新。 在实现监听器的过程中, 可以通过调用 getAnimatedValue() 来获取到那次特定 的动画帧更新事件中的计算值。欲知更多关于监听 器的信息,则参考 动画监听 器 小节。
ObjectAnimator 是 ValueAnimator 的一个子类(前面已经说过 了 ), 它将以下功能结合起来了:时序引擎 ; ValueAnimator 的值计算功能;以及, 对目标对象的某个命名属性进行动画的能力。 这样,对任何对象进行动画的工作就变得容易得多了,因为 ,妳不需要实现 ValueAnimator.AnimatorUpdateListener 了,那些 被动画的属性会自动更新。
ObjectAnimator 的实例化与 ValueAnimator 类似,但是, 除了动画的值范围之外,妳还需要提供动画 的目标对象及它的某个属性的名字(以String 的形式提供):
ObjectAnimator anim = ObjectAnimator . ofFloat ( foo , "alpha" , 0f , 1f );
anim . setDuration ( 1000 );
anim . start ();
为了让 ObjectAnimator 能够正确的更新属性,妳必须做到以下事情:
•. 妳要对其进行动画的那个对象属性,必须拥有一个设值函数 ( 以骆驼风格命名 ) ,其形式为 set<propertyName>() 。因为 ObjectAnimator 会在动画过程中自动地更新目标属性 ,所以, 它必须能够使用该设值方法来访问到目标属性。例如 ,如果 该属性的名字是 foo ,那么,妳需要实现一个 setFoo() 方法。如果 该设值方法不存在,那么,妳有三种选择:
•.如果妳拥有相应的权限,那么,向那个类中加入这样一个设值方法。
•.使用某个妳有权限更改的包装类,让那些包装类以一个有效的设值方法来接收属性值,并且将该属性值转发给原始对象。
•. 使用 ValueAnimator 。
•. 如果 妳在 ObjectAnimator 的工厂方法中 只针对 values... 参数指定了一个值,那么,系统 就会假设 妳所设置的是该动画的结束值。 这样的话, 妳要对其进行动画的那个对象属性,必须拥有 一个取值函数,用来获取动画的起始值。取值函数 的形式必须是 get<propertyName>() 。例如,属性名字 是 foo ,则,需要有一个 getFoo() 方法。
•. 妳在对其进行动画的那个属性的 取值 (如果需要的话)和设值方法, 其对应的数据类型,必须与妳向 ObjectAnimator 指定的起始值和终止值的类型相同。例如 ,假设 妳按照以下的代码来构造 ObjectAnimator ,那么, 就必须拥有 targetObject.setPropName(float) 和 targetObject.getPropName(float) 方法:
ObjectAnimator . ofFloat ( targetObject , "propName" , 1f )
•. 取决 于妳在对什么属性或对象进行动画, 妳可能需要 对某个View 调用其 invalidate() 方法,以强迫屏幕按照更新后的动画值来重绘。 妳可以在 onAnimationUpdate() 回调方法中做这件事。例如, 当妳 对某个Drawable 对象进行动画时, 只有在那个对象重绘自身的情况下, 才会引 起 屏幕画面更新。View 的所有属性设置方法,例如 setAlpha() 和 setTranslationX() ,都会正确地将该View 标记为无效,因此 ,当妳使用这些方法来设置新的值的时候,无需显式地将该View 标记为无效。欲知更多关于监听 器的信息,则参考关于 动画监听 器 的小节。
在狠多情况下, 妳都需要让一个动画在另一个动画结束之后才开始。安卓系统允许 妳将多个动画捆绑成为一个 AnimatorSet ,这样,妳就可以指定,多个动画 是要并行启动、串行化启动还是要在延迟一段时间之后启动。 妳还可以将多个 AnimatorSet 对象嵌套起来。
以下示例代码,取自 跳跳球球 示例( 经过了简化 ),会按照下列规则来播放以下 Animator 对象:
1. 播放 bounceAnim 。
2. 同时 播放 squashAnim1 、 squashAnim2 、 stretchAnim1 和 stretchAnim2 。
3. 播放 bounceBackAnim 。
4. 播放 fadeAnim 。
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 ();
欲学习 一个关于如何使用动画器集合的完整示例,则参考APIDemos 中的 跳跳球球 示例。
妳可以使用下列监听器来监听动画持续过程中的那些重要事件。
•. onAnimationStart() - 当动画启动时,会调用此方法。
•. onAnimationEnd() - 当动画结束时,会调用此方法。
•. onAnimationRepeat() - 当动画重复时,会调用此方法。
•. onAnimationCancel() - 当动画取消时,会调用此方法。 被取消的动画,也会调用 onAnimationEnd() 。
•. ValueAnimator.AnimatorUpdateListener
•. onAnimationUpdate() - 在该动画的每一帧,都会调用此方法。监听 这个事件,以便使用动画过程中由 ValueAnimator 生成的计算值。 要使用该值,则,调用传递 到这个事件中的那个 ValueAnimator 对象的 getAnimatedValue() 方法来获取到当前动画值。如果 妳使用 ValueAnimator 的话,那么,这个监听器是必定要实现的。
取决 于妳在对什么属性或对象进行动画, 妳可能需要 对某个View 调用其 invalidate() 方法,以强迫屏幕按照更新后的动画值来重绘。 妳可以在 onAnimationUpdate() 回调方法中做这件事。例如, 当妳 对某个Drawable 对象进行动画时, 只有在那个对象重绘自身的情况下, 才会引 起 屏幕画面更新。View 的所有属性设置方法,例如 setAlpha() 和 setTranslationX() ,都会正确地将该View 标记为无效,因此 ,当妳使用这些方法来设置新的值的时候,无需显式地将该View 标记为无效。
如果 妳并不想实现 Animator.AnimatorListener 接口中的所有方法,那么,妳可以扩展 AnimatorListenerAdapter 类,而不是实现 Animator.AnimatorListener 接口。 AnimatorListenerAdapter 类提供了那些方法的空白实现, 而妳可以按照需要来覆盖 。
例如,应用编程接口演示 中的 跳跳球球 示例,创建了一个 AnimatorListenerAdapter ,并且只是实现了 onAnimationEnd() 回调方法:
ValueAnimatorAnimator fadeAnim = ObjectAnimator . ofFloat ( newBall , "alpha" , 1f , 0f );
fadeAnim . setDuration ( 250 );
fadeAnim . addListener ( new AnimatorListenerAdapter () {
public void onAnimationEnd ( Animator animation ) {
balls . remove ((( ObjectAnimator ) animation ). getTarget ());
}
属性动画系统,除了提供了一种轻易地对 View 对象进行动画的手段之外,还提供了对于ViewGroup 对象的变更情况进行动画的能力。
妳可以使用 LayoutTransition 类来 对ViewGroup 中的布局变更进行动画。ViewGroup 中的那些Views,可以在以下情况下呈现出一个出现动画 或消失动画: 妳 向ViewGroup 中添加它们,或者从 ViewGroup 中删除它们; 妳使用 VISIBLE 、android.view.View#INVISIBLE 或 GONE 参数来调用某个View 的 setVisibility() 方法。 当妳添加或删除Views 的时候,该ViewGroup 中的其它Views 也可以以动画形式移动到各自的新位置。 妳可以 在某个 LayoutTransition 对象中定义以下动画,具体做法 就是,调用 setAnimator() ,并且传入一个 Animator 对象,以及以下的某个 LayoutTransition 常量:
•. APPEARING - 这个标志位,表明, 这个动画针对的是那些正在某个容器中出现的条目。
•. CHANGE_APPEARING - 这个标志位,表明,这个动画针对的是那些因容器 中 某个新条目的出现而 发生改变的条目。
•. DISAPPEARING - 这个标志位,表明, 这个动画针对的是那些正从某个容器中消失的条目。
•. CHANGE_DISAPPEARING - 这个标志位,表明,这个动画针对的是那些因容器中某个条目的消失而发 生改变的条目。
妳可以定义针对这四种事件的自定义动画,以对妳的布局转场效果进行自定义。或者,直接告诉动画系统要使用默认动画。
应用编程接口演示 中的 LayoutAnimations 示例,演示 了,如何定义针对布局 转场过程的动画,并且 ,将这些动画设置到妳 想要展现出动画效果的View 对象上。
LayoutAnimationsByDefault 和对应的 layout_animations_by_default.xml 布局资源文件,演示了,如何 为XML 中的那些ViewGroups 启用默认的布局转场效果。 妳所需要做的唯一一件事情就是, 将该ViewGroup 的 android:animateLayoutchanges 属性设置为 true 。例如:
<LinearLayout
android:orientation = "vertical"
android:layout_width = "wrap_content"
android:layout_height = "match_parent"
android:id = "@+id/verticalContainer"
android:animateLayoutChanges = "true" />
将这个属性设置为真(true),就会自动地为ViewGroup 中那些被添加或删除的Views 以及ViewGroup 中的其它Views 展现动画效果。
如果 妳想针对安卓系统所不理解的数据类型进行动画,那么, 妳可以通 过 实现 TypeEvaluator 接口来创建自己的算值器。安卓系统能够理解 的数据类型包括 int 、 float 和颜色值,分别 由 IntEvaluator 、 FloatEvaluator 和 ArgbEvaluator 3个类型算值器来提供支持。
在 TypeEvaluator 接口中,只需要实现一个方法,即 evaluate() 方法。利用 这个方法, 妳所使用的那个动画器就可以针对当前 的动画时间来返回 一个适当的属性值。 FloatEvaluator 类展示了如何实现这一点:
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 参数接收到的,就是这个插值后的版本,因此 , 在计算动画值时,妳无需再将插值计算在内了。
插值器,定义的是,使用什么样的一个关于时间的函数来计算出动画中的特定值。例如,妳可以指定,让动画在整个过程中线性发展,也就是说,整个过程中,动画都是匀速呈现的。或者,也可以指定,动 画使用非线性时间来发展,例如,在动画的开始或结尾阶段使用加速或减速。
动画系统 中的 插值 器,从Animators 处接收一个百分比,表示的是,动画的逝去时间。然后 , 插值 器修改这个百分比,以符合 它所提供的动画类型的要求。安卓系统 在 android.view.animation 包 中提供了一组常用插值器。如果 这些插值器都不符合妳的需求,那么,可以实现 TimeInterpolator 接口,以创建自己的插值器。
作为示例 ,在下面,比较了默认插值器 AccelerateDecelerateInterpolator 和 LinearInterpolator 之间 在 计算插值百分比时的差异。 LinearInterpolator 对于逝去百分 比不产生任何影响。 AccelerateDecelerateInterpolator ,最初会以加速的形式进入动画,最后以减速的形式离开动画。下列方法定义 了这些插值器的逻辑:
AccelerateDecelerateInterpolator
public float getInterpolation ( float input ) {
return ( float )( Math . cos (( input + 1 ) * Math . PI ) / 2.0f ) + 0.5f ;
}
LinearInterpolator
public float getInterpolation ( float input ) {
return input ;
}
下表中,对于一个持续1000毫秒的动画,显示出了两个插值器计算出的近似值:
逝去的毫秒数 |
逝去百分比/插值百分比(线性) |
插值百分比(加速/减速) |
0 |
0 |
0 |
200 |
.2 |
.1 |
400 |
.4 |
.345 |
600 |
.6 |
.8 |
800 |
.8 |
.9 |
1000 |
1 |
1 |
从表中可以看到, LinearInterpolator 会以恒定的速度来改变值,每隔200毫秒便改变.2。 而 AccelerateDecelerateInterpolator 呢,跟 LinearInterpolator 相比, 在200毫秒到600毫秒的时间段里,会让值变化得快一些,而在600毫秒到1000毫秒的时间段之内,会让值变化得慢一些。
Keyframe 对象 ,由一个键/值对组成, 可让妳定义出在动画 的特定时间具有的一个特定状态。每个关键 帧, 还可以拥有它自己的插值器,用来控制, 在前一个关键帧到这个关键帧之间的时间段里,动画的行为。
要想实例化一个 Keyframe 对象, 妳必须使用 ofInt() 、 ofFloat() 或 ofObject() 中的某个工厂方法来获取一个适当类型 的 Keyframe 。然后 ,调用 ofKeyframe() 工厂方法来获取一个 PropertyValuesHolder 对象。 当妳获取了这个对象之后, 就可以调用某个方法,并且传入该 PropertyValuesHolder 对象和要进行动画的那个对象,来获取一个动画器。 以下代码片断即为示例:
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 ( 5000ms );
欲学习一个更完整的关于使用关键帧的示例,则参考APIDemos 中的 MultiPropertyAnimation 示例。
属性动画系统使得妳能够以流水线的方式为View 对象创建动画,并且,相对于视图动画系统,还提供了若干优势。视图动画系统,通过改变各个对象的绘制方式来产生出变换效果。这个过程是由各个View 的容器来完成的,因为,View 本身并不有相应的可操作的属性。其结果就是,View会呈现出动画效果,然而,该View 对象本身并无变化。由此会产生一些奇特的行为,例如,即使某个对象被绘制到了屏幕上狠远的位置,它实际上仍然处于自己原来所在的位置。从安卓3.0开始,引入了新的属性及对应的取值、设值方法,于是就去掉了这个缺陷。
属性动画系统 ,通过改变View 对象 的实际属性来 让Views 在屏幕上呈现动画效果。另外 , Views ,在其属性被改变时,也会自动调用 invalidate() 方法来更新屏幕。 View 类中,用来支持属性动画的那些新属性 , 如下所示:
•. translationX 和 translationY : 这些属性,控制的是, 该View 相对于其左侧坐标和顶部坐标的偏移值, 后两者是由其布局容器设置的。
•. rotation 、 rotationX 和 rotationY : 这些属性,控制的是, 以支点为基础, 该对象所具有的二维旋转角度( rotation 属性)和三维旋转角度。
•. scaleX 和 scaleY : 这些属性,控制的是, 以其支点为中心, 该View 的二维缩放比例。
•. pivotX 和 pivotY : 这些属性,控制的是,支点 的位置,旋转 和缩放变换就是以支点为中心的。默认情况 下,支点位于该对象的中心。
•. x 和 y : 这些属性,起到辅助 的作用,描述的是 该View 在其容器中的最终位置值 。分别等价 于,左侧坐标 值和顶部坐标值加上translationX 和translationY 值之后的结果。
•. alpha :代表着该View 的透明度。默认 值是 1(完全 不透明 ) ,如果 值为 0 则代表完全透明 ( 不可见 ) 。
要想对某个View 对象的属性进行动画,例如它的颜色或旋转值,妳所需要做的事情就是,创建一个属性动画器,并且指定妳要对其进行动画的View 属性。例如:
ObjectAnimator . ofFloat ( myView , "rotation" , 0f , 360f );
欲知更多关于创建动画 器的信息,则参考使用 ValueAnimator 和 ObjectAnimator 进行动画的小节。
ViewPropertyAnimator 提供 了一种简单的方式,可利用单个底层的 Animator 对象来同时 对某个 View 的多个属性进行动画。 它的行为与 ObjectAnimator 类似,因为 , 它修改该视图的属性的实际值,但是, 在同时对 多个属性进行动画时,它更高效 。另外 , 在使用 ViewPropertyAnimator 的时候,所写的代码, 更简洁,更易读。 以下代码片断,展示 了,使用不同的手段来 同时对某个视图的 x 和 y 属性进行动画的区别:使用多个 ObjectAnimator 对象 ;使用单个 ObjectAnimator ;以及,使用 ViewPropertyAnimator 。
多个ObjectAnimator对象
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
PropertyValuesHolder pvhX = PropertyValuesHolder . ofFloat ( "x" , 50f );
PropertyValuesHolder pvhY = PropertyValuesHolder . ofFloat ( "y" , 100f );
ObjectAnimator . ofPropertyValuesHolder ( myView , pvhX , pvyY ). start ();
ViewPropertyAnimator
myView . animate (). x ( 50f ). y ( 100f );
欲知更多关于 ViewPropertyAnimator 的信息,则参考对应 的安卓开发者 勃客文章 。
属性动画系统,允许妳利用XML 来声明属性动画,而不是使用代码来声明。通过在XML 中定义动画,妳可以轻易地将动画在多个活动中复用,并且,更轻易地编辑动画序列。
为了将那些使用新的属性动画应用编程接口的动画文件与使用旧式 视图动画 框架的动画文件区分开来, 从安卓 3.1开始 , 妳应当将那些针对属性动画的 XML文件保存 到 res/animator/ 目录( 而不是 res/anim/ ) 中。使用 animator 这个目录名,是可选的,但是 ,如果 妳想要在Eclipse ADT 插件(ADT 11.0.0+)中使用布局编辑器的话,则是必需的,因为 , ADT 只会在 res/animator/ 目录中搜索属性动画资源。
以下属性动画类支持通过XML 来声明,并且,我们还给出了对应的XML 标记:
•. ValueAnimator - <animator>
•. ObjectAnimator - <objectAnimator>
•. AnimatorSet - <set>
以下示例中,串行地播放两个对象动画集合,并且,第一个嵌套动画集合中,并行地播放两个对象动画:
<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 的所有子代动画设置好单个目标对象。 以下代码即为一个示例:
AnimatorSet set = ( AnimatorSet ) AnimatorInflater . loadAnimator ( myContext ,
R . anim . property_animator );
set . setTarget ( myObject );
set . start ();
欲知更多关于定义属性动画 时的XML 语法的信息,则阅读 动画资源 。
未知美人
流水不腐
Your opinionsHxLauncher: Launch Android applications by voice commands