page.title=Animation @jd:body
The Android system provides a flexible animation system that allows you to animate almost anything, either programmatically or declaratively with XML. There are two animation systems that you can choose from: property animation and view animation. You can use whichever system that matches your needs, but use only one system for each object that you are animating.
Introduced in Android 3.0, the property animation system allows you to animate
object properties of any type. int
, float
,
and hexadecimal color values are supported by default. You can animate any other type by telling the
system how to calculate the values for that given type.
The property animation system allows you to define many aspects of an animation, such as:
Most of the property animation system's features can be found in {@link android.animation android.animation}. Because the Animating with ValueAnimator for more information.
If you are animating an object property that is not an int
,
float
, or color, implement the {@link android.animation.TypeEvaluator}
interface to specify how to compute the object property's animated values. You give
a {@link android.animation.TypeEvaluator} the timing data that is provided by an
{@link android.animation.Animator} class, the animation's start and end value, and
provide logic that computes the animated values of the property based on this data.
You can also specify a custom {@link android.animation.TypeEvaluator} for
int
, float
, and color values as well, if you want to
process those types differently than the default behavior.
See Using a TypeEvaluator for more information on how to write a custom evaluator.
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, using acceleration or deceleration at the beginning or end of the animation.
The Android system provides a set of common interpolators in {@link android.view.animation android.view.animation}. If none of these suits your needs, you can implement the {@link android.animation.TimeInterpolator} interface and create your own. See Interpolators for more information on how to write a custom interpolator.
The com.example.android.apis.animation
package in the
API Demos sample project also provides a good overview and many examples on how to
use the property animation system.
When you call {@link android.animation.ValueAnimator#start start()} to begin an animation, the {@link android.animation.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%. The Animator then calls the {@link android.animation.TimeInterpolator} that is currently set, to calculate an eased fraction, which is a modified value of the elapsed fraction that takes into account the interpolator that is set (time interpolation is often referred to as easing). The eased fraction is the final value that is used to animate the property.
Once the eased fraction is calculated, {@link android.animation.ValueAnimator} calls the appropriate {@link android.animation.TypeEvaluator} to calculate the final value of the property that you are animating, based on the eased fraction, the starting value, and ending value of the animation.
The {@link android.animation.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 over and the duration of the animation.
You obtain a {@link android.animation.ValueAnimator} by calling one of its factory
methods: {@link android.animation.ValueAnimator#ofInt ofInt()},
{@link android.animation.ValueAnimator#ofFloat ofFloat()},
or {@link android.animation.ValueAnimator#ofObject ofObject()}. For example:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); animation.setDuration(1000); animation.start();
In this code, the {@link android.animation.ValueAnimator} starts
calculating the values of the animation, between 0 and 1, for
a duration of 1000 ms, when the start()
method runs.
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 {@link android.animation.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 {@link android.animation.ValueAnimator#start start()}
method runs.
The previous code snippets, however, do not affect an object, because the {@link android.animation.ValueAnimator} does not operate on objects or properties directly. To use the results of a {@link android.animation.ValueAnimator}, you must define listeners in the {@link android.animation.ValueAnimator} to appropriately handle important events during the animation's lifespan, such as frame updates. You can implement the following interfaces to create listeners for {@link android.animation.ValueAnimator}:
{@link android.animation.ValueAnimator.AnimatorUpdateListener#onAnimationUpdate onAnimationUpdate()} - called on every frame of the animation. Listen to this event to use the calculated values generated by {@link android.animation.ValueAnimator} during an animation. To use the value, query the {@link android.animation.ValueAnimator} object passed into the event to get the current animated value with the {@link android.animation.ValueAnimator#getAnimatedValue getAnimatedValue()} method.
If you are animating your own custom object (not View objects), this callback must also call the {@link android.view.View#invalidate invalidate()} method to force a redraw of the screen. If you are animating View objects, {@link android.view.View#invalidate invalidate()} is automatically called when a property of the View is changed.
You can extend the {@link android.animation.AnimatorListenerAdapter} class instead of implementing the {@link android.animation.Animator.AnimatorListener} interface, if you do not want to implement all of the methods of the {@link android.animation.Animator.AnimatorListener} interface. The {@link android.animation.AnimatorListenerAdapter} class provides empty implementations of the methods that you can choose to override.
For example, the Bouncing Balls sample in the API demos creates an {@link android.animation.AnimatorListenerAdapter} for just the {@link android.animation.Animator.AnimatorListener#onAnimationEnd onAnimationEnd()} callback:
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()); }
The {@link android.animation.ObjectAnimator} is a subclass of the {@link android.animation.ValueAnimator} (discussed in the previous section) and combines the timing engine and value computation of {@link android.animation.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 {@link android.animation.ValueAnimator.AnimatorUpdateListener}, because the animated property updates automatically.
Instantiating an {@link android.animation.ObjectAnimator} is similar to a {@link android.animation.ValueAnimator}, but you also specify the object and that object's property (as a String) that you want to animate:
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f); anim.setDuration(1000); anim.start();
To have the {@link android.animation.ObjectAnimator} update properties correctly, you must do the following:
set<propertyName>()
. Because the {@link
android.animation.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:
values...
parameter,
in one of the {@link android.animation.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<propertyName>()
. For example, if the property name is
foo
, you need to have a getFoo()
method.targetObject.setPropName(float)
and
targetObject.getPropName(float)
if you construct the following {@link
android.animation.ObjectAnimator}:
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
If you want to animate a type that is unknown to the Android system,
you can create your own evaluator by implementing the {@link
android.animation.TypeEvaluator} interface. The types that are known by the Android
system are int
, float
, or a color, which are supported by the
{@link android.animation.IntEvaluator}, {@link android.animation.FloatEvaluator}, and
{@link android.animation.ArgbEvaluator} type evaluators.
There is only one method to implement in the {@link android.animation.TypeEvaluator} interface, the {@link android.animation.TypeEvaluator#evaluate 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 {@link android.animation.FloatEvaluator} class demonstrates how to do this:
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 {@link android.animation.ValueAnimator} (or
{@link android.animation.ObjectAnimator}) runs, it calculates a current elapsed
fraction of the animation (a value between 0 and 1) and then calculates an eased
version of that depending on what interpolator that you are using. The eased fraction
is what your {@link android.animation.TypeEvaluator} receives through the fraction
parameter, so you do not have to take into account the interpolator
when calculating animated values.
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 {@link android.view.animation android.view.animation package}. If none of these suit your needs, you can implement the {@link android.animation.TimeInterpolator} interface and create your own.
As an example, how the default interpolator {@link android.view.animation.AccelerateDecelerateInterpolator} and the {@link android.view.animation.LinearInterpolator} calculate eased fractions are compared below. The {@link android.view.animation.LinearInterpolator} has no effect on the elapsed fraction, because a linear interpolation is calculated the same way as the elapsed fraction. The {@link android.view.animation.AccelerateDecelerateInterpolator} accelerates into the animation and decelerates out of it. The following methods define the logic for these interpolators:
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:
ms elapsed | Elapsed fraction/Eased fraction (Linear) | Eased fraction (Accelerate/Decelerate) |
---|---|---|
0 | 0 | 0 |
200 | .2 | .1 |
400 | .4 | .345 |
600 | .6 | .8 |
800 | .8 | .9 |
1000 | 1 | 1 |
As the table shows, the {@link android.view.animation.LinearInterpolator} changes the values at the same speed, .2 for every 200ms that passes. The {@link android.view.animation.AccelerateDecelerateInterpolator} changes the values faster than {@link android.view.animation.LinearInterpolator} between 200ms and 600ms and slower between 600ms and 1000ms.
A {@link android.animation.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 {@link android.animation.Keyframe} object, you must use one of the factory methods, {@link android.animation.Keyframe#ofInt ofInt()}, {@link android.animation.Keyframe#ofFloat ofFloat()}, or {@link android.animation.Keyframe#ofObject ofObject()} to obtain the appropriate type of {@link android.animation.Keyframe}. You then call the {@link android.animation.PropertyValuesHolder#ofKeyframe ofKeyframe()} factory method to obtain a {@link android.animation.PropertyValuesHolder} object. Once you have the object, you can obtain an animator by passing in the {@link android.animation.PropertyValuesHolder} object and the object to animate. The following code snippet demonstrates how to do this:
Keyframe kf0 = Keyframe.ofFloat(0f, 0f); Keyframe kf1 = Keyframe.ofFloat(.9999f, 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.
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 {@link android.animation.AnimatorSet}, so that you can specify whether to start animations simultaneously, sequentially, or after a specified delay. You can also nest {@link android.animation.AnimatorSet} objects within each other.
The following sample code taken from the Bouncing Balls sample (modified for simplicity) plays the following {@link android.animation.Animator} objects in the following manner:
bounceAnim
.squashAnim1
, squashAnim2
,
stretchAnim1
, and stretchAnim2
at the same time.bounceBackAnim
.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.
As with view animation, you can declare property animations with XML instead of doing it programmatically. The following Android classes also have XML declaration support with the following XML tags:
<animator>
<objectAnimator>
<AnimatorSet>
Both <animator>
({@link android.animation.ValueAnimator}) and
<objectAnimator>
({@link android.animation.ObjectAnimator}) have the
following attributes:
android:duration
android:valueFrom
and android:valueTo
float
or int
) in
XML. They can be float
, int
, or any kind of
Object
when creating animations programmatically.android:valueType
"floatType"
or "intType"
.android:startDelay
android:repeatCount
"-1"
for infinite repeating or to a positive integer. For example, a value of
"1"
means that the animation is repeated once after the initial run of the
animation, so the animation plays a total of two times. The default value is
"0"
.android:repeatMode
android:repeatCount
must be set to a positive integer or
"-1"
for this attribute to have an effect. Set to "reverse"
to
have the animation reverse direction with each iteration or "repeat"
to
have the animation loop from the beginning each time.The objectAnimator
({@link android.animation.ObjectAnimator}) element has the
additional attribute propertyName
, that lets you specify the name of the
property being animated. The objectAnimator
element does not expose a
target
attribute, however, so you cannot set the object to animate in the
XML declaration. You have to inflate the XML resource by calling
{@link android.animation.AnimatorInflater#loadAnimator loadAnimator()} and call
{@link android.animation.ObjectAnimator#setTarget setTarget()} to set the target object, before calling
{@link android.animation.ObjectAnimator#start start()}.
The set
element ({@link android.animation.AnimatorSet}) exposes a single
attribute, ordering
. Set this attribute to together
(default)
to play all the animations in this set at once. Set this attribute to
sequentially
to play the animations in the order they are declared.
You can specify nested set
tags to further group animations together.
The animations that you want to group together should be children of the
set
tag and can define their own ordering
attribute.
As an example, this XML code creates an {@link android.animation.AnimatorSet} object
that animates x and y at the same time (together
is the default ordering
when nothing is specified), then runs an animation that fades an object out:
<set android:ordering="sequentially"> <set> <objectAnimator android:propertyName="x" android:duration="500" android:valueTo="400" android:valueType="int"/> <objectAnimator android:propertyName="y" android:duration="500" android:valueTo="300" android:valueType="int" > </set> <objectAnimator android:propertyName="alpha" android:duration="500" android:valueTo="0f"/> </set>
In order to run this animation, you must inflate the XML resources in your code to an {@link android.animation.AnimatorSet} object, and then set the target objects for all of the animations before starting the animation set. Calling {@link android.animation.AnimatorSet#setTarget setTarget()} sets a single target object for all children of the {@link android.animation.AnimatorSet}.
A tween animation can perform a series of simple transformations (position, size, rotation, and transparency) on the contents of a View object. So, if you have a {@link android.widget.TextView} object, you can move, rotate, grow, or shrink the text. If it has a background image, the background image will be transformed along with the text. The {@link android.view.animation animation package} provides all the classes used in a tween animation.
A sequence of animation instructions defines the tween animation, defined by either XML or Android code. As with defining a layout, an XML file is recommended because it's more readable, reusable, and swappable than hard-coding the animation. In the example below, we use XML. (To learn more about defining an animation in your application code, instead of XML, refer to the {@link android.view.animation.AnimationSet} class and other {@link android.view.animation.Animation} subclasses.)
The animation instructions define the transformations that you want to occur, when they will occur, and how long they should take to apply. Transformations can be sequential or simultaneous — for example, you can have the contents of a TextView move from left to right, and then rotate 180 degrees, or you can have the text move and rotate simultaneously. Each transformation takes a set of parameters specific for that transformation (starting size and ending size for size change, starting angle and ending angle for rotation, and so on), and also a set of common parameters (for instance, start time and duration). To make several transformations happen simultaneously, give them the same start time; to make them sequential, calculate the start time plus the duration of the preceding transformation.
The animation XML file belongs in the res/anim/
directory of your
Android project. The file must have a single root element: this will be either a single
<alpha>
, <scale>
, <translate>
,
<rotate>
, interpolator element, or <set>
element
that holds groups of these elements (which may include another
<set>
). By default, all animation instructions are applied
simultaneously. To make them occur sequentially, you must specify the
startOffset
attribute, as shown in the example below.
The following XML from one of the ApiDemos is used to stretch, then simultaneously spin and rotate a View object.
<set android:shareInterpolator="false"> <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:fromXScale="1.0" android:toXScale="1.4" android:fromYScale="1.0" android:toYScale="0.6" android:pivotX="50%" android:pivotY="50%" android:fillAfter="false" android:duration="700" /> <set android:interpolator="@android:anim/decelerate_interpolator"> <scale android:fromXScale="1.4" android:toXScale="0.0" android:fromYScale="0.6" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:startOffset="700" android:duration="400" android:fillBefore="false" /> <rotate android:fromDegrees="0" android:toDegrees="-45" android:toYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:startOffset="700" android:duration="400" /> </set> </set>
Screen coordinates (not used in this example) are (0,0) at the upper left hand corner, and increase as you go down and to the right.
Some values, such as pivotX, can be specified relative to the object itself or relative to the parent. Be sure to use the proper format for what you want ("50" for 50% relative to the parent, or "50%" for 50% relative to itself).
You can determine how a transformation is applied over time by assigning an {@link android.view.animation.Interpolator}. Android includes several Interpolator subclasses that specify various speed curves: for instance, {@link android.view.animation.AccelerateInterpolator} tells a transformation to start slow and speed up. Each one has an attribute value that can be applied in the XML.
With this XML saved as hyperspace_jump.xml
in the
res/anim/
directory of the project, the following code will reference
it and apply it to an {@link android.widget.ImageView} object from the layout.
ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage); Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump); spaceshipImage.startAnimation(hyperspaceJumpAnimation);
As an alternative to startAnimation()
, you can define a starting time
for the animation with {@link android.view.animation.Animation#setStartTime(long)
Animation.setStartTime()}
, then assign the animation to the View with
{@link android.view.View#setAnimation(android.view.animation.Animation)
View.setAnimation()}
.
For more information on the XML syntax, available tags and attributes, see Animation Resources.
Note: Regardless of how your animation may move or resize, the bounds of the View that holds your animation will not automatically adjust to accommodate it. Even so, the animation will still be drawn beyond the bounds of its View and will not be clipped. However, clipping will occur if the animation exceeds the bounds of the parent View.
This is a traditional animation in the sense that it is created with a sequence of different images, played in order, like a roll of film. The {@link android.graphics.drawable.AnimationDrawable} class is the basis for frame animations.
While you can define the frames of an animation in your code, using the {@link
android.graphics.drawable.AnimationDrawable} class API, it's more simply accomplished
with a single XML file that lists the frames that compose the animation. Like the tween
animation above, the XML file for this kind of animation belongs in the
res/drawable/
directory of your Android project. In this case, the
instructions are the order and duration for each frame of the animation.
The XML file consists of an <animation-list>
element as the root
node and a series of child <item>
nodes that each define a frame: a
drawable resource for the frame and the frame duration. Here's an example XML file for
a frame-by-frame animation:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true"> <item android:drawable="@drawable/rocket_thrust1" android:duration="200" /> <item android:drawable="@drawable/rocket_thrust2" android:duration="200" /> <item android:drawable="@drawable/rocket_thrust3" android:duration="200" /> </animation-list>
This animation runs for just three frames. By setting the
android:oneshot
attribute of the list to true, it will cycle
just once then stop and hold on the last frame. If it is set false then the
animation will loop. With this XML saved as rocket_thrust.xml
in the
res/drawable/
directory of the project, it can be added as the background
image to a View and then called to play. Here's an example Activity, in which the
animation is added to an {@link android.widget.ImageView} and then animated when the
screen is touched:
AnimationDrawable rocketAnimation; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image); rocketImage.setBackgroundResource(R.drawable.rocket_thrust); rocketAnimation = (AnimationDrawable) rocketImage.getBackground(); } public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { rocketAnimation.start(); return true; } return super.onTouchEvent(event); }
It's important to note that the start()
method called on the
AnimationDrawable cannot be called during the onCreate()
method of your
Activity, because the AnimationDrawable is not yet fully attached to the window. If you
want to play the animation immediately, without requiring interaction, then you might
want to call it from the {@link
android.app.Activity#onWindowFocusChanged(boolean) onWindowFocusChanged()}
method in your Activity, which will get called when Android brings your window into
focus.
For more information on the XML syntax, available tags and attributes, see Animation Resources.