Android官方文档阅读之旅——Property Animation 属性动画

Android官方文档阅读之旅——Property Animation 属性动画

原文地址:http://developer.android.com/guide/topics/graphics/prop-animation.html#object-animator

The property animation system is a robust framework that allows you to animate almost anything. You can define an animation to change any object property over time, regardless of whether it draws to the screen or not. A property animation changes a property’s (a field in an object) value over a specified length of time. To animate something, you specify the object property that you want to animate, such as an object’s position on the screen, how long you want to animate it for, and what values you want to animate between.

属性动画系统是一种非常强健的架构,它允许你对任何东西设置动画。你可以定义一个在一段时间后改变任何对象属性的动画,无论这个图形是否已被绘制到屏幕上。一个属性动画在第一段时间后会改变一个属性值(对象中的一个字段)。在绘制动画时,你需要指定需要改变的对象属性,如对象在屏幕中的位置、时长以及属性值变动的区间。

The property animation system lets you define the following characteristics of an animation:

  • Duration: You can specify the duration of an animation. The default length is 300 ms.
  • Time interpolation: You can specify how the values for the property are calculated as a function of the animation’s current elapsed time.
  • Repeat count and behavior: You can specify whether or not to have an animation repeat when it reaches the end of a duration and how many times to repeat the animation. You can also specify whether you want the animation to play back in reverse. Setting it to reverse plays the animation forwards then backwards repeatedly, until the number of repeats is reached.
  • Animator sets: You can group animations into logical sets that play together or sequentially or after specified delays.
  • Frame refresh delay: You can specify how often to refresh frames of your animation. The default is set to refresh every 10 ms, but the speed in which your application can refresh fromames is ultimately dependent on how busy the system is overall and how fast the system can service the underlying timer.

属性动画系统允许你定义如下几种动画特性:

  • 时长:你可以指定动画的时长,默认300ms
  • 时间插值:你可以指定这个属性值应该如何被计算。计算由一个关于动画进行时长的函数负责。
  • 重复次数和重复的行为:你可以指定当动画完成时是否重复动画以及重复动画的次数。你也可以指定是否需要动画再逆向播放一遍。可以将动画设置为往复进行直到达到重复上限。
  • 动画集:你可以将多个动画组织成为一个集合并可在一段指定时间后同时或顺序播放它们
  • 帧刷新延迟:你可以指定动画的帧刷新频率。默认值为每10ms刷新一次。但是刷新的速率最终由系统总体负荷以及其对此计时器的响应速度决定。

How Property Animation Works 属性动画工作原理

First, let’s go over how an animation works with a simple example. Figure 1 depicts a hypothetical object that is animated with its x property, which represents its horizontal location on a screen. The duration of the animation is set to 40 ms and the distance to travel is 40 pixels. Every 10 ms, which is the default frame refresh rate, the object moves horizontally by 10 pixels. At the end of 40ms, the animation stops, and the object ends at horizontal position 40. This is an example of an animation with linear interpolation, meaning the object moves at a constant speed.

animation-linear

首先我们通过一个简单的例子看一下动画是如何工作的。图一描绘了一个假定的物体在X轴位置属性上进行动画的场景,表现为其在屏幕水平位置的移动。动画时长为40ms,移动距离为40像素。每10ms(这是预定的刷新频率),它就会水平移动10像素。在40ms后,动画停止,并且物体终止于水平位置上的第40像素的位置。这是一个具有线性插值动画的例子,意味着物体将以一固定速度运动。

You can also specify animations to have a non-linear interpolation. Figure 2 illustrates a hypothetical object that accelerates at the beginning of the animation, and decelerates at the end of the animation. The object still moves 40 pixels in 40 ms, but non-linearly. In the beginning, this animation accelerates up to the halfway point then decelerates from the halfway point until the end of the animation. As Figure 2 shows, the distance traveled at the beginning and end of the animation is less than in the middle.

animation-nonlinear

你也可以为动画设定非线性插值。图二则展示一个假定的物体在动画开始时进行加速,并在动画结束时减速的例子。物体在40ms中移动了40像素,但是移动过程呈非线性。起初,物体在路程中的一点前加速运动,并在另一点后减速。正如图二所示,物体在两端运动的距离比中间部分的距离要短。

Let’s take a detailed look at how the important components of the property animation system would calculate animations like the ones illustrated above. Figure 3 depicts how the main classes work with one another.

valueanimator

让我们仔细看一下这些重要的属性动画系统组件是如何计算如上所述动画的。图三说明了这些类间的关系。

The ValueAnimator object keeps track of your animation’s timing, such as how long the animation has been running, and the current value of the property that it is animating.

ValueAnimator 对象会时刻跟进你的动画,如动画已经运行了多久以及当前正在进行动画展示的属性的值。

The ValueAnimator encapsulates a TimeInterpolator, which defines animation interpolation, and a TypeEvaluator, which defines how to calculate values for the property being animated. For example, in Figure 2, the TimeInterpolator used would be AccelerateDecelerateInterpolator and the TypeEvaluator would be IntEvaluator.

ValueAnimator封装了一个TimeInterpolator(它定义了一个动画插值),以及一个TypeEvaluator(它定义了如何计算被动画展示的属性的值)。例如,在图二中,这个TimeInterpolator将被用作为加减速动画插值,而这个TypeEvaluator将会被用作为IntEvaluator。

To start an animation, create a ValueAnimator and give it the starting and ending values for the property that you want to animate, along with the duration of the animation. When you call start() the animation begins. During the whole animation, the ValueAnimator calculates an elapsed fraction between 0 and 1, based on the duration of the animation and how much time has elapsed. The elapsed fraction represents the percentage of time that the animation has completed, 0 meaning 0% and 1 meaning 100%. For example, in Figure 1, the elapsed fraction at t = 10 ms would be .25 because the total duration is t = 40 ms.

为了启动一个动画,你需要创建一个ValueAnimator并确定需要动画展示的属性起止值,同时指定动画时长。当你调用start()时,动画开始。在整个过程中,它会计算一个介于0到1的进行百分比。此计算依赖于动画总时长以及已经进行的时长。这个百分比表明了动画已经完成了多少。0 意味着 0%, 1 意味着 100%。比如,在图一中,在10ms时的完成百分比就是25%,因为总是长为40ms

When the ValueAnimator is done calculating an elapsed fraction, it calls the TimeInterpolator that is currently set, to calculate an interpolated fraction. An interpolated fraction maps the elapsed fraction to a new fraction that takes into account the time interpolation that is set. For example, in Figure 2, because the animation slowly accelerates, the interpolated fraction, about .15, is less than the elapsed fraction, .25, at t = 10 ms. In Figure 1, the interpolated fraction is always the same as the elapsed fraction.

当ValueAnimator计算完一个当前进度百分比时,它就会调用当前设置的TimeInterpolator来计算一个插值。插值会根据当前设定的动画插值函数将当前完成百分比映射到一个新的比值上去。例如,在图二中,由于动画是缓慢加速的,此时插值为0.15,比10ms时动画完成比率0.25要低一些。在图一中,插值恒等于动画完成比率。

When the interpolated fraction is calculated, ValueAnimator calls the appropriate TypeEvaluator, to calculate the value of the property that you are animating, based on the interpolated fraction, the starting value, and the ending value of the animation. For example, in Figure 2, the interpolated fraction was .15 at t = 10 ms, so the value for the property at that time would be .15 X (40 - 0), or 6.

当插值被计算出来时,ValueAnimator就会调用合适的TypeEvaluator从而计算出合适的属性值。计算基于插值、属性开始值以及属性结束值。例如,在图二中,在10ms时的插值为0.15,那么此时的属性值就应该为 0.15*(40 - 0)也就是 6 。

The com.example.android.apis.animation package in the API Demos sample project provides many examples on how to use the property animation system.

com.example.android.apis.animation 包中的API使用样例工程提供了一个关于如何使用属性动画系统的例子。

How Property Animation Differs from View Animation 属性动画同补间动画之区别

The view animation system provides the capability to only animate View objects, so if you wanted to animate non-View objects, you have to implement your own code to do so. The view animation system is also constrained in the fact that it only exposes a few aspects of a View object to animate, such as the scaling and rotation of a View but not the background color, for instance.

补间动画提供了对View对象执行动画的能力,所以如果你想对非View对象进行动画操作的话,你不得不自己通过代码实现。实际上,视图控件系统因这样的一个问题而受到了约束,那就是它仅对部分的View属性可进行动画展示,如放大和旋转。但是对于更改背景色等情况却无能为力。

Another disadvantage of the view animation system is that it only modified where the View was drawn, and not the actual View itself. For instance, if you animated a button to move across the screen, the button draws correctly, but the actual location where you can click the button does not change, so you have to implement your own logic to handle this.

它另一个弊端就是仅对View的绘制区域进行改动,而非实际View本身。例如,如果你让一个button从屏幕中穿过,那么button会被正确的绘制,但是按键的热区并没有被改变,所以你不得不用自己的逻辑处理此类情况。

With the property animation system, these constraints are completely removed, and you can animate any property of any object (Views and non-Views) and the object itself is actually modified. The property animation system is also more robust in the way it carries out animation. At a high level, you assign animators to the properties that you want to animate, such as color, position, or size and can define aspects of the animation such as interpolation and synchronization of multiple animators.

对于属性动画而言,就完全不存在这样的约束。并且你可对任何对象,不管是否为View对象,和任何属性进行动画操作,并且对象本身的属性会被真实改变。在执行动画方面,属性动画系统也表现的十分强劲。从顶层的使用角度看,你可以为想要进行动画展示的属性,如颜色、位置或大小分配animator。并且可以定义动画的属性如插值以及多动画同步操作。

The view animation system, however, takes less time to setup and requires less code to write. If view animation accomplishes everything that you need to do, or if your existing code already works the way you want, there is no need to use the property animation system. It also might make sense to use both animation systems for different situations if the use case arises.

但是视图动画系统启动时间更短,并且需要的代码量更少。如果此系统可以满足你的所需,或者目前你的代码已经达到了你的需求,那么此时就无需使用属性动画系统。根据不同情况以及用例触发条件兼用两种系统是十分明智的。

API Overview API 概述

You can find most of the property animation system’s APIs in android.animation. Because the view animation system already defines many interpolators in android.view.animation, you can use those interpolators in the property animation system as well. The following tables describe the main components of the property animation system.

你可以在android.animation 中找到绝大多数属性动画系统API。由于视图空间动画系统已经在android.view.animation 中定义了很多动画插值,你也可以在属性动画中使用这些插值。下面的表格介绍了属性动画系统中主要的组件。

The Animator class provides the basic structure for creating animations. You normally do not use this class directly as it only provides minimal functionality that must be extended to fully support animating values. The following subclasses extend Animator:

Animator类提供了创建动画的基本结构。你无需使用直接使用这个类因为它仅仅提供了最小支持(译者注:也就是一系列接口),且它必须被其他的类扩展(实现)以完全支持动画效果。下面几个子类扩展自Animator:

ClassDescription
ValueAnimatorThe main timing engine for property animation that also computes the values for the property to be animated. It has all of the core functionality that calculates animation values and contains the timing details of each animation, information about whether an animation repeats, listeners that receive update events, and the ability to set custom types to evaluate. There are two pieces to animating properties: calculating the animated values and setting those values on the object and property that is being animated. ValueAnimator does not carry out the second piece, so you must listen for updates to values calculated by the ValueAnimator and modify the objects that you want to animate with your own logic. See the section about Animating with ValueAnimator for more information.
ObjectAnimatorA subclass of ValueAnimator that allows you to set a target object and object property to animate. This class updates the property accordingly when it computes a new value for the animation. You want to use ObjectAnimator most of the time, because it makes the process of animating values on target objects much easier. However, you sometimes want to use ValueAnimator directly because ObjectAnimator has a few more restrictions, such as requiring specific acessor methods to be present on the target object.
AnimationSetProvides a mechanism to group animations together so that they run in relation to one another. You can set animations to play together, sequentially, or after a specified delay. See the section about Choreographing multiple animations with Animator Sets for more information.
描述
ValueAnimator属性动画的主要时序引擎,并且也会计算被动画展示的属性的值。它具有所有计算属性值的核心方法,也包含了每种动画的时序细节、动画是否重复的信息、用于监听动画更新事件的监听器,同时具有评估自定义类型的能力。播放属性动画有两点内容:计算属性值以及将它们设置到对象和对应属性上去。ValueAnimator做不到第二点,你必须监听由它计算更新的属性值,并修改对应的正在按照你自己的逻辑进行动画播放的对象。
ObjectAnimator一个ValueAnimator的子类。它允许你设定将被动画展示的对象以及属性。这个类在为播放动画而计算完成一个新的属性值时,它就会相应地更新这个对象的属性。由于该类让在目标对象上设置动画效果的过程更加容易便捷,你可能在大多数情况下考虑使用它。但是某些情况下你也必须直接使用ValueAnimator,因为ObjectAnimator较其相比有较多的约束性,如它需要具体的对目标对象的存取方法
AnimationSet它提供了组合动画的机制,这样动画间的播放就可以存在一种相互依赖的关系。你可以将这些动画同时播放、顺序播放或者延迟播放。更多信息请参见文档“利用动画集合编排多动画效果”部分。

Evaluators tell the property animation system how to calculate values for a given property. They take the timing data that is provided by an Animator class, the animation’s start and end value, and calculate the animated values of the property based on this data. The property animation system provides the following evaluators:

估值器告诉了系统如何计算给定属性的值。它们将由Animator类提供的时序数据以及动画的起止值作为参数,并以此计算动画效果对应的属性值。属性动画系统提供了如下的几种估值器:

ClassDescription
IntEvaluatorThe default evaluator to calculate values for int properties.
FloatEvaluatorThe default evaluator to calculate values for float properties.
ArgbEvaluatorThe default evaluator to calculate values for color properties that are represented as hexidecimal values.
TypeEvaluatorAn interface that allows you to create your own evaluator. If you are animating an object property that is not an int, float, or color, you must implement the TypeEvaluator interface to specify how to compute the object property’s animated values. You can also specify a custom TypeEvaluator for int, float, and color values as well, if you want to process those types differently than the default behavior. See the section about Using a TypeEvaluator for more information on how to write a custom evaluator.
描述
IntEvaluator计算整型属性的默认估值器
FloatEvaluator计算浮点型属性的默认估值器
ArgbEvaluator计算十六进制表示的颜色属性的默认估值器
TypeEvaluator允许你创建自己定义估值器的一个接口。如果你正在播放一个非整数型、非浮点型或非颜色型属性的动画, 那么你就必须实现此接口以指定如何计算这个属性的值。 如果你想改变这些类型默认的属性值计算方式 ,你也可以自定义对应的TypeEvaluator。关于自定义TypeEvaluator的更多信息,请参阅文档中关于使用TypeEvaluator的部分。

A time interpolator defines how specific values in an animation are calculated as a function of time. For example, you can specify animations to happen linearly across the whole animation, meaning the animation moves evenly the entire time, or you can specify animations to use non-linear time, for example, accelerating at the beginning and decelerating at the end of the animation. Table 3 describes the interpolators that are contained in android.view.animation. If none of the provided interpolators suits your needs, implement the TimeInterpolator interface and create your own. See Using interpolators for more information on how to write a custom interpolator.

动画插值是一个以时间为参数的函数。它定义了动画中一些特定值的计算。例如,你可指定动画在整个过程中以线性方式或非线性方式呈现。所谓线性就是在整个动画过程中匀速运动。对于非线性,举例来说,就是一类在开始阶段加速,结尾阶段减速的这么一种动画形式。表3描述了包含在android.view.animation中的插值。如果它们都未能满足你的需求,那么就可通过实现TimeInterpolator接口来创建自己的插值。关于自定义插值,请参阅文档插值使用的相关章节。

ClassDescription
AccelerateDecelerateInterpolatorAn interpolator whose rate of change starts and ends slowly but accelerates through the middle.
AccelerateInterpolatorAn interpolator whose rate of change starts out slowly and then accelerates.
AnticipateInterpolatorAn interpolator whose change starts backward then flings forward.
AnticipateOvershootInterpolatorAn interpolator whose change starts backward, flings forward and overshoots the target value, then finally goes back to the final value.
BounceInterpolatorAn interpolator whose change bounces at the end.
CycleInterpolatorAn interpolator whose animation repeats for a specified number of cycles.
DecelerateInterpolatorAn interpolator whose rate of change starts out quickly and and then decelerates.
LinearInterpolatorAn interpolator whose rate of change is constant.
OvershootInterpolatorAn interpolator whose change flings forward and overshoots the last value then comes back.
TimeInterpolatorAn interface that allows you to implement your own interpolator.
描述
AccelerateDecelerateInterpolator在起止附近改变较慢但在中间处改变较快的插值
AccelerateInterpolator改变频率在开始较慢,然后加速的插值
AnticipateInterpolator改变频率在初期为负然后正向快速加速的插值
AnticipateOvershootInterpolator改变频率在初期为负数再向正向加速至越过目标值,最后返回目标
BounceInterpolator改变频率在末期具有反弹效果
CycleInterpolator以指定的周期重复动画,改变频率曲线为正弦。
DecelerateInterpolator改变频率开始比较快然后减速
LinearInterpolator改变频率恒定
OvershootInterpolator改变率开始向正向加速至越过目标值,最后返回目标
TimeInterpolator一个允许你自定义时间插值的接口

Animating with ValueAnimator 利用ValueAnimator播放动画

The ValueAnimator class lets you animate values of some type for the duration of an animation by specifying a set of int, float, or color values to animate through. You obtain a ValueAnimator by calling one of its factory methods: ofInt(), ofFloat(), or ofObject(). For example:

你可以使用ValueAnimator播放一些类型的属性动画。你可以在整个动画过程中指定需要播放的一组整数型、浮点型或者颜色类型的属性值。获取一个ValueAnimator对象需要调用 ofInt()、ofFloat()或ofObject()这三个工厂方法中的一个。比如你可以这样写代码:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();

In this code, the ValueAnimator starts calculating the values of the animation, between 0 and 1, for a duration of 1000 ms, when the start() method runs.

在这段代码中,当start()方法调用时,ValueAnimator开始就会在1000ms的动画时长里从0到1地计算动画值。

You can also specify a custom type to animate by doing the following:

你也可以像这样对自定义类型进行设置动画效果。

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator()
    , startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

In this code, the ValueAnimator starts calculating the values of the animation, between startPropertyValue and endPropertyValue using the logic supplied by MyTypeEvaluator for a duration of 1000 ms, when the start() method runs.

在这段代码中,当start()方法调用时,ValueAnimator就会开始在1000ms的动画过程中,从startPropertyValue到endPropertyValue间利用提供的MyTypeEvaluator逻辑计算动画的属性值。

The previous code snippets, however, has no real effect on an object, because the ValueAnimator does not operate on objects or properties directly. The most likely thing that you want to do is modify the objects that you want to animate with these calculated values. You do this by defining listeners in the ValueAnimator to appropriately handle important events during the animation’s lifespan, such as frame updates. When implementing the listeners, you can obtain the calculated value for that specific frame refresh by calling getAnimatedValue(). For more information on listeners, see the section about Animation Listeners.

然而前面的代码片段并不会对一个对象产生影响。因为ValueAnimator并不直接对对象或属性进行操作。而你最有可能想要做的事情就是利用这些计算的值改变需要进行动画展示的对象,为此你需要在ValueAnimator中定义监听器,并在监听器中处理动画过程的重要事件,如帧更新事件。当你实现了这些监听器时,你就可以通过调用getAnimatedValue()获得为刷新帧而计算的属性值。关于监听器的更多内容请参阅文档动画监听器部分。

Animating with ObjectAnimator 利用ObjectAnimator进行播放动画

The ObjectAnimator is a subclass of the ValueAnimator (discussed in the previous section) and combines the timing engine and value computation of ValueAnimator with the ability to animate a named property of a target object. This makes animating any object much easier, as you no longer need to implement the ValueAnimator.AnimatorUpdateListener, because the animated property updates automatically.

ObjectAnimator继承自ValueAnimator(如前文所述),并且包含了时序引擎,ValueAnimator的属性值计算以及对给定的目标对象属性进行动画展示的能力。这让对任何对象设置动画变得更加容易,因为你无需再实现ValueAnimator.AnimatorUpdateListener监听器,属性值的更新都是自动完成的。

Instantiating an ObjectAnimator is similar to a ValueAnimator, but you also specify the object and the name of that object’s property (as a String) along with the values to animate between:

实例化一个ObjectAnimator比实例化一个ValueAnimator更加容易。但是在指定动画起止值的同时,你也必须指定具体的对象以及需要处理的对象属性(以字符串形式传入):

ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();

To have the ObjectAnimator update properties correctly, you must do the following:

  • The object property that you are animating must have a setter function (in camel case) in the form of set(). Because the ObjectAnimator automatically updates the property during animation, it must be able to access the property with this setter method. For example, if the property name is foo, you need to have a setFoo() method. If this setter method does not exist, you have three options:
    • Add the setter method to the class if you have the rights to do so.
    • Use a wrapper class that you have rights to change and have that wrapper receive the value with a valid setter method and forward it to the original object.
    • Use ValueAnimator instead.
  • If you specify only one value for the values… parameter in one of the ObjectAnimator factory methods, it is assumed to be the ending value of the animation. Therefore, the object property that you are animating must have a getter function that is used to obtain the starting value of the animation. The getter function must be in the form of get(). For example, if the property name is foo, you need to have a getFoo() method.
  • The getter (if needed) and setter methods of the property that you are animating must operate on the same type as the starting and ending values that you specify to ObjectAnimator. For example, you must have targetObject.setPropName(float) and targetObject.getPropName(float) if you construct the following ObjectAnimator:
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
  • Depending on what property or object you are animating, you might need to call the invalidate() method on a View to force the screen to redraw itself with the updated animated values. You do this in the onAnimationUpdate() callback. For example, animating the color property of a Drawable object only cause updates to the screen when that object redraws itself. All of the property setters on View, such as setAlpha() and setTranslationX() invalidate the View properly, so you do not need to invalidate the View when calling these methods with new values. For more information on listeners, see the section about Animation Listeners.

为了让ObjectAnimator能正确的更新属性,你必须做以下的几个事情。

  • 进行动画展示的对象属性必须有一个set()形式的设置方法(以驼峰式大小写命名)。因为在动画过程中属性的更新是由ObjectAnimator自动处理的,ObjectAnimator必须可通过这个设置方法处理属性。例如,如果有个属性名称为foo,那么你就需要提供一个setFoo()方法。如果这个方法不存在,那么你具有以下三种备选方案:
    • 向这个类添加set方法如果你具备这样的权限
    • 使用一个你有权修改的包装类,并让这个包装类可通过一个有效的set方法获得计算的属性值,并将其传入到原来的对象中去
    • 改用ValueAnimator
  • 如果你在ObjectAnimator工厂方法的values…参数表中仅传入了一个值,那么系统就会将其视为动画的结束值。因此,如果需要获得动画开始值,那么被动画展示的对象属性就必须具有一个获取方法,其形式也必须为get()形。例如,如果这个属性名为foo,那么你就必须提供一个getFoo()方法。
  • 当你在向ObjectAnimator指定起止值时,进行动画展示的属性的get方法(如果需要)和set方法具有相同的参数类型。例如,如果你想像下面这样构建一个ObjectAnimator的话,那么你就必须提供targetObject.setPropName(float) 和 targetObject.getPropName(float)方法。
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
  • 根据你要进行动画展示的属性以及对象,你可能需要在一个View中调用invalidate()方法强制重绘此控件并更新属性值。你可在onAnimationUpdated()回调中进行这样的操作。例如,当你对一个Drawable对象进行变色的动画时,仅当控件自行重绘时才会引起屏幕显示效果的更新。View的所有set方法,如setAlpha()和setTranslationX()方法会对View进行恰当的重绘,因此在调用这些方法并传入新的属性值时,你无须自行对控件进程重绘。对于监听器的更多信息,请参见文档动画监听器部分。

Choreographing Multiple Animations with AnimatorSet 利用AnimatorSet编排多动画效果

In many cases, you want to play an animation that depends on when another animation starts or finishes. The Android system lets you bundle animations together into an AnimatorSet, so that you can specify whether to start animations simultaneously, sequentially, or after a specified delay. You can also nest AnimatorSet objects within each other.

很多情况下,你想要根据一个动画的起止来安排另一个动画的播放。安卓系统允许你将多种动画编排在一起并放入一个AnimatorSet中。这样一来你就可以安排是否将这些动画同时播放,顺序播放亦或是延迟一段时间后再播放。你也可以将多个AnimatorSet对象联系起来。

The following sample code taken from the Bouncing Balls sample (modified for simplicity) plays the following Animator objects in the following manner:

  1. Plays bounceAnim.
  2. Plays squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2 at the same time.
  3. Plays bounceBackAnim.
  4. Plays fadeAnim.

下面的这段代码来自于“弹动的球”样例Demo(为了简化而进行了更改)。这个Demo按照如下规则播放了多个Animator对象。

  1. 播放 bounceAnim
  2. 同时播放 squashAnim1, squashAnim2, stretchAnim1, and 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();

For a more complete example on how to use animator sets, see the Bouncing Balls sample in APIDemos.

关于如何使用动画集合的一个更加完整的案例,请参考APIDemos中的“弹球”案例。

Animation Listeners 动画监听器

You can listen for important events during an animation’s duration with the listeners described below.

  • Animator.AnimatorListener
    • onAnimationStart() - Called when the animation starts.
    • onAnimationEnd() - Called when the animation ends.
    • onAnimationRepeat() - Called when the animation repeats itself.
    • onAnimationCancel() - Called when the animation is canceled. A cancelled animation also calls onAnimationEnd(), regardless of how they were ended.
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate() - called on every frame of the animation. Listen to this event to use the calculated values generated by ValueAnimator during an animation. To use the value, query the ValueAnimator object passed into the event to get the current animated value with the getAnimatedValue() method. Implementing this listener is required if you use ValueAnimator.
      Depending on what property or object you are animating, you might need to call invalidate() on a View to force that area of the screen to redraw itself with the new animated values. For example, animating the color property of a Drawable object only cause updates to the screen when that object redraws itself. All of the property setters on View, such as setAlpha() and setTranslationX() invalidate the View properly, so you do not need to invalidate the View when calling these methods with new values.

你可利用在如下所述监听器对动画中的重要事件进行监听

  • Animator.AnimatorListener
    • onAnimationStart() - 在动画开始时调用。
    • onAnimationEnd() - 在动画结束时调用。
    • onAnimationRepeat() - 当动画重复时调用。
    • onAnimationCancel() - 在动画结束时调用,此时也会触发onAnimationEnd()。onAnimtionEnd()的触发与动画结束的方式无关。
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate() - 动画的每一帧都会调用此方法。监听这个事件的目的是利用动画过程中ValueAnimator所计算出来的值。为此,你需要查询传入此事件的ValueAnimator对象,并调用getAnimatedValue()方法来获取当前进度下的属性值。如果你使用ValueAnimator的话那就必须实现这个监听器。

      根据你要进行动画展示的属性以及对象,你可能需要在一个View中调用invalidate()方法强制重绘此控件并更新属性值。你可在onAnimationUpdated()回调中进行这样的操作。例如,当你对一个Drawable对象进行变色的动画时,仅当控件自行重绘时才会引起屏幕显示效果的更新。View的所有set方法,如setAlpha()和setTranslationX()方法会对View进行恰当的重绘,因此在调用这些方法并传入新的属性值时,你无须自行对控件进程重绘。

You can extend the AnimatorListenerAdapter class instead of implementing the Animator.AnimatorListener interface, if you do not want to implement all of the methods of the Animator.AnimatorListener interface. The AnimatorListenerAdapter class provides empty implementations of the methods that you can choose to override.

你如果不想实现实现Animator.AnimatorListener接口的所有方法,那么也可以继承AnimatorListenerAdapter类。此类提供了对此接口所有方法的空实现,你可依据需求对其中的方法进行复写。

For example, the Bouncing Balls sample in the API demos creates an AnimatorListenerAdapter for just the onAnimationEnd() callback:

例如,API使用案例中的“弹球”案例为了仅回调onAnimationEnd()就创建一个AnimatorListenerAdapter。

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());
}

对ViewGroup设置布局改变的动画

The property animation system provides the capability to animate changes to ViewGroup objects as well as provide an easy way to animate View objects themselves.

属性动画系统提供了对ViewGroup对象的属性改变进行动画展示的能力,同时也对View对象本身设置动画提供了一种更加简便的方式。

You can animate layout changes within a ViewGroup with the LayoutTransition class. Views inside a ViewGroup can go through an appearing and disappearing animation when you add them to or remove them from a ViewGroup or when you call a View’s setVisibility() method with VISIBLE, android.view.View#INVISIBLE}, or GONE. The remaining Views in the ViewGroup can also animate into their new positions when you add or remove Views. You can define the following animations in a LayoutTransition object by calling setAnimator() and passing in an Animator object with one of the following LayoutTransition constants:

通过LayoutTransition类,你可以对ViewGroup对象内的布局改动以动画形式展现。当你向一个ViewGroup对象中添加或者删除View时,或者当你调用这些View的setVisibility()方法传入VISIBLE、INVISIBLE或GONE参数时,这些View就可以进行展现或消失的动画。ViewGroup中其他的View可以通过动画的形式移动到新的位置,当你向其中增删View时。你可以在一个LayoutTransition中定义如下的动画。为此,你需要调用setAnimator()方法并向这个Animator对象中传入如下的LayoutTransition常量中的一个:

  • APPEARING - A flag indicating the animation that runs on items that are appearing in the container.
  • CHANGE_APPEARING - A flag indicating the animation that runs on items that are changing due to a new item appearing in the container.
  • DISAPPEARING - A flag indicating the animation that runs on items that are disappearing from the container.
  • CHANGE_DISAPPEARING - A flag indicating the animation that runs on items that are changing due to an item disappearing from the container.
  • APPEARING - 一个标记,表明动画发生于将在容器中出现的对象的身上。
  • CHANGE_APPEARING - 一个标记,表明动画发生在容器中正在进行改变的对象的身上,且改变的原因为一个新的对象即将出现在容器中
  • DISAPPEARING - 一个标记,表明动画发生于将在容器中消失的对象的身上。
  • CHANGE_APPEARING - 一个标记,表面表明动画发生在容器中正在进行改变的对象的身上,且改变的原因为一个对象即将在容器中消失

You can define your own custom animations for these four types of events to customize the look of your layout transitions or just tell the animation system to use the default animations.

你可对这四种类型的事件定制你自己的动画形式。这样,你就可以自定义布局改动时的样式。或者直接告诉系统使用默认动画效果。

The LayoutAnimations sample in API Demos shows you how to define animations for layout transitions and then set the animations on the View objects that you want to animate.

在API Demo中的LayoutAnimations使用样例向你展示了如何为布局改动制定动画以及如何在这之后,为你想动画展示的View对象设置动画效果。

The LayoutAnimationsByDefault and its corresponding layout_animations_by_default.xml layout resource file show you how to enable the default layout transitions for ViewGroups in XML. The only thing that you need to do is to set the android:animateLayoutchanges attribute to true for the ViewGroup. For example:

这个LayoutAnimationByDefault的案例以及其对应的layout_animations_by_default.xml的布局资源文件向你展示了如何在XML中为ViewGroup对象设置默认的布局改动动画。你仅需要做的一件事情就是对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" />

Setting this attribute to true automatically animates Views that are added or removed from the ViewGroup as well as the remaining Views in the ViewGroup.

将这个属性设为真时,系统就会自动地为添加到ViewGroup中,或对从ViewGroup中移除的View自动播放动画。同时系统也会为ViewGroup中其他的View播放布局改变时的动画。

Using a TypeEvaluator 使用一个TypeEvaluator

If you want to animate a type that is unknown to the Android system, you can create your own evaluator by implementing the TypeEvaluator interface. The types that are known by the Android system are int, float, or a color, which are supported by the IntEvaluator, FloatEvaluator, and ArgbEvaluator type evaluators.

如果你想对一个Android系统未知的属性类型进行动画展示时,那么你就可以实现TypeEvaluator接口并创建一个自己估值器。Android系统已知的类型为int、float或者为color类型。支持它们三个的对应的估值器为 IntEvaluator, FloatEvaluator, 和 ArgbEvaluator。

There is only one method to implement in the TypeEvaluator interface, the evaluate() method. This allows the animator that you are using to return an appropriate value for your animated property at the current point of the animation. The FloatEvaluator class demonstrates how to do this:

在TypeEvaluator接口中只有一个需要实现的方法,那就是evaluate()。此方法允许你正在使用的animator对象在动画的当前进度上,为你正在展示的属性返回一个恰当的值。这个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);
    }
}

Note: When ValueAnimator (or ObjectAnimator) runs, it calculates a current elapsed fraction of the animation (a value between 0 and 1) and then calculates an interpolated version of that depending on what interpolator that you are using. The interpolated fraction is what your TypeEvaluator receives through the fraction parameter, so you do not have to take into account the interpolator when calculating animated values.

注意:当一个ValueAnimator(或者是ObjectAnimator)运行时,它会计算一个当前动画的完成百分比(一个介于0到1的值),然后计算一个对应插值。插值的计算依赖于你究竟使用哪个插值。这个插值就是你的TypeEvaluator通过fraction参数获取的,所以当你在计算动画值时就无需考虑插值的计算了。

Using Interpolators 使用插值

An interpolator define how specific values in an animation are calculated as a function of time. For example, you can specify animations to happen linearly across the whole animation, meaning the animation moves evenly the entire time, or you can specify animations to use non-linear time, for example, using acceleration or deceleration at the beginning or end of the animation.

动画插值是一个以时间为参数的函数。它定义了动画中一些特定值的计算。例如,你可指定动画在整个过程中以线性方式或非线性方式呈现。所谓线性就是在整个动画过程中匀速运动。对于非线性,举例来说,就是一类在开始阶段加速,结尾阶段减速的这么一种动画形式。

Interpolators in the animation system receive a fraction from Animators that represent the elapsed time of the animation. Interpolators modify this fraction to coincide with the type of animation that it aims to provide. The Android system provides a set of common interpolators in the android.view.animation package. If none of these suit your needs, you can implement the TimeInterpolator interface and create your own.

动画系统中的插值会从Animator对象中获取一个比值。这个比值表明了当前动画的进度。插值为了和将要被提供的动画的类型统一,它会对这个比值进行修改。安卓系统提供了一系列常见的插值,它们都在andriod.view.animation包中。如果这些都没能满足你的要求,你可以通过实现TimeInterpolator接口来创建你自己的插值。

As an example, how the default interpolator AccelerateDecelerateInterpolator and the LinearInterpolator calculate interpolated fractions are compared below. The LinearInterpolator has no effect on the elapsed fraction. The AccelerateDecelerateInterpolator accelerates into the animation and decelerates out of it. The following methods define the logic for these interpolators:

作为例子,我们将默认的两个插值, AccelerateDecelerateInterpolator 以及 LinearInterpolator,计算插值的过程在下面做个了一个比较。线性插值对动画完成比是没有效果的。这个加减速插值以加速方式进入动画,以减速方式退出动画。下面的方法定义了这两种插值器的计算逻辑:

//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;
}

The following table represents the approximate values that are calculated by these interpolators for an animation that lasts 1000ms:

下面的表格写出了这两个插值为1000ms时长动画所计算的插值的近似值。

ms elapsed 动画进度(单位:ms)Elapsed fraction/Interpolated fraction (Linear) 动画完成百分比/插值(线性)Interpolated fraction (Accelerate/Decelerate) 插值(加速/减速)
000
200.2.1
400.4.345
600.6.8
800.8.9
100011

As the table shows, the LinearInterpolator changes the values at the same speed, .2 for every 200ms that passes. The AccelerateDecelerateInterpolator changes the values faster than LinearInterpolator between 200ms and 600ms and slower between 600ms and 1000ms.

如表格所示,线性插值以匀速改变插值,每200ms增加0.2。加减速插值器在[200,600]区间里更改较慢,在[600,1000]区间里更改较快。

Specifying Keyframes 指明关键帧

A Keyframe object consists of a time/value pair that lets you define a specific state at a specific time of an animation. Each keyframe can also have its own interpolator to control the behavior of the animation in the interval between the previous keyframe’s time and the time of this keyframe.

一个关键帧对象包含了一组时间为键,数值为值的键值对。这个键值对帮助你在动画的某一特定时间里定义某一种特定的状态。每个关键帧对象也可以有自己的插值。这样就能在此关键帧和前一个关键帧的时间间隔中控制动画的行为。

To instantiate a Keyframe object, you must use one of the factory methods, ofInt(), ofFloat(), or ofObject() to obtain the appropriate type of Keyframe. You then call the ofKeyframe() factory method to obtain a PropertyValuesHolder object. Once you have the object, you can obtain an animator by passing in the PropertyValuesHolder object and the object to animate. The following code snippet demonstrates how to do this:

为了能实例化一个关键帧对象,你必须使用 ofInt(), ofFloat(), 或 ofObject()这三个工厂方法中的一个来获取合适类型的关键帧对象。然后你需要调用ofKeyframe()工厂方法来获得一个PropertyValuesHolder对象。一旦你拥有这个对象,你就可以通过向其传参的方式获得一个animator对象以及需要动画展示的object。下面的代码片段说明了如果做到这些:

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);

For a more complete example on how to use keyframes, see the MultiPropertyAnimation sample in APIDemos.
关于一个更加完整的keyframe使用案例,参见API Demo中的MultiPropertyAnimation。

Animating Views 对View设置动画效果

The property animation system allow streamlined animation of View objects and offers a few advantages over the view animation system. The view animation system transformed View objects by changing the way that they were drawn. This was handled in the container of each View, because the View itself had no properties to manipulate. This resulted in the View being animated, but caused no change in the View object itself. This led to behavior such as an object still existing in its original location, even though it was drawn on a different location on the screen. In Android 3.0, new properties and the corresponding getter and setter methods were added to eliminate this drawback.

属性动画系统允许为View对象绑定一系列动画效果,并提供了相比补间动画更多的优势。补间动画通过改变绘制方式来改变View对象。这些都在每个View的容器中进行,因为View自己没有可操作的属性。这就导致了虽然对View施加了动画效果,但是其本身的属性并没有被改变。这也导致了这样一类的行为:就算一个对象被绘制到了另外一处,但是它的实际位置(有效区域)还在原处。Android 3.0 提供了新的属性以及配套的get和set方法来弥补这一缺陷。

The property animation system can animate Views on the screen by changing the actual properties in the View objects. In addition, Views also automatically call the invalidate() method to refresh the screen whenever its properties are changed. The new properties in the View class that facilitate property animations are:

属性动画系统却可以通过更改View的实际属性来实现动画效果。此外,无论何时属性被更改,View对象们都会自动调用invalidate()来刷新屏幕显示。这些在View类中,提升属性动画的新属性就是:

  • translationX and translationY: These properties control where the View is located as a delta from its left and top coordinates which are set by its layout container.
  • rotation, rotationX, and rotationY: These properties control the rotation in 2D (rotation property) and 3D around the pivot point.
  • scaleX and scaleY: These properties control the 2D scaling of a View around its pivot point.
  • pivotX and pivotY: These properties control the location of the pivot point, around which the rotation and scaling transforms occur. By default, the pivot point is located at the center of the object.
  • x and y: These are simple utility properties to describe the final location of the View in its container, as a sum of the left and top values and translationX and translationY values.
  • alpha: Represents the alpha transparency on the View. This value is 1 (opaque) by default, with a value of 0 representing full transparency (not visible).
  • translationX 和 translationY: 这些属性将控制容器所安排的View在左面和上面两种坐标位置的偏移量。
  • rotation, rotationX, 和 rotationY:这些属性控制绕转轴的二维(旋转属性)和三维的旋转动画。
  • scaleX 和 scaleY:根据中心点在二维平面上对View进行缩放
  • pivotX 和 pivotY:控制View的中心点,这会对旋转和缩放造成影响。默认情况下,中心点位于一个对象的中心。
  • x 和 y:这是两个简单的工具属性,用于描述View在容器中的最终位置。它们的值等于left值、right值、translationX值和translationY值的和。
  • alpha:表示View的alpha透明度。默认为1(不透明),最小为0表示全透明(不可见)。

To animate a property of a View object, such as its color or rotation value, all you need to do is create a property animator and specify the View property that you want to animate. For example:

为了给View对象的一个属性(如颜色或者旋转的值)设置动画,你只需创建一个属性动画对象,并指定属性。比如:

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

For more information on creating animators, see the sections on animating with ValueAnimator and ObjectAnimator.

关于创建动画的更多信息,参见ValueAnimator和ObjectAnimator部分

Animating with ViewPropertyAnimator 利用ViewPropertyAnimator播放动画

The ViewPropertyAnimator provides a simple way to animate several properties of a View in parallel, using a single underlying Animator object. It behaves much like an ObjectAnimator, because it modifies the actual values of the view’s properties, but is more efficient when animating many properties at once. In addition, the code for using the ViewPropertyAnimator is much more concise and easier to read. The following code snippets show the differences in using multiple ObjectAnimator objects, a single ObjectAnimator, and the ViewPropertyAnimator when simultaneously animating the x and y property of a view.

ViewPropertyAnimator利用内置的Animator对象提供了一种对同一View的多种属性同时播放属性动画的简单方法。它运作起来特别像一个ObjectAnimator,因为它更改了View的实际属性值。但是相比而言,它在同时播放多种属性动画上更加高效。此外,ViewPropertyAnimator的代码也更加简洁易读。下面的代码片段展示了使用多ObjectAnimator对象、一个ObjectAnimator对象和ViewPropertyAnimator对象在同时对View的X与Y属性进行动画的不同。

Multiple ObjectAnimator objects

使用多个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();

One ObjectAnimator

使用一个ObjectAnimator对象

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

ViewPropertyAnimator

使用ViewPropertyAnimator对象

myView.animate().x(50f).y(100f);

Declaring Animations in XML 在XML中定义动画

The property animation system lets you declare property animations with XML instead of doing it programmatically. By defining your animations in XML, you can easily reuse your animations in multiple activities and more easily edit the animation sequence.

属性动画系统允许你不在代码中定义动画,而是在XML中定义。通过在XML中定义动画,你可以在不同Activity间更容易地复用你的动画,并可以更加容易地编辑动画序列。

To distinguish animation files that use the new property animation APIs from those that use the legacy view animation framework, starting with Android 3.1, you should save the XML files for property animations in the res/animator/ directory (instead of res/anim/). Using the animator directory name is optional, but necessary if you want to use the layout editor tools in the Eclipse ADT plugin (ADT 11.0.0+), because ADT only searches the res/animator/ directory for property animation resources.

一些新的属性动画API从Android 3.1才开始推出。为了区分使用新老动画框架的动画文件,你应该在 res/animator/ 目录下而非 res/anim/目录下保存XML属性动画文件。你也可以随意选择是否使用Animator这个目录名,不过有一种情况下你必须使用它,那就是当你希望使用Eclipse ADT插件(ADT 11.0.0+)中的布局编辑器。因为ADT仅仅在 res/animator 的目录下寻找属性动画资源。

The following property animation classes have XML declaration support with the following XML tags:

以下几个属性动画类支持通过使用如下标签在XML定义动画的功能

  • ValueAnimator -
  • ObjectAnimator -
  • AnimatorSet -

The following example plays the two sets of object animations sequentially, with the first nested set playing two object animations together:

以下的例子连续播放了两个对象动画的集合。其中第一个的集合同时播放了两个对象动画。

<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>

In order to run this animation, you must inflate the XML resources in your code to an AnimatorSet object, and then set the target objects for all of the animations before starting the animation set. Calling setTarget() sets a single target object for all children of the AnimatorSet as a convenience. The following code shows how to do this:

为了播放这个动画,你必须在代码中实现这个XML资源并把它加载到一个AnimatorSet对象上,并在开始播放这个动画集合前,把所有的目标对象设置到动画中去。为了方便,你可以调用setTarget()为动画集合的所有子动画设置一个唯一的目标对象。下面的代码展示了如何这样去做:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
set.setTarget(myObject);
set.start();

For information about the XML syntax for defining property animations, see Animation Resources.

关于定义属性动画的XML语法的更多信息,参见《动画资源》部分


由于笔者水平有限,内容仅供参考,如有翻译不当之处,欢迎指正

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值