Sie sind auf Seite 1von 32

10 Understanding Animation

Introduction
Android supports two kinds of animation. One is called "Tweened Animation". The second one is called
"Frame by Frame" animation. "Tween" is a short for "in-between" borrowed from traditional animators.
Inbetweens are drawings that simulate motion between key frames. There may be 24 inbetweens between
two key frames or there could be 12 between two key frames. The former case is called "on ones" and the
later ones are called "on twos".
In Android here is how "tweening" works. You start with a view. This view can be any view including a view
group with any set of complex composed graphical objects. When tweening animation is attached to this
view, the animation gets a call back at regular intervals to change any aspect of the tranformation matrix
that would be used to render the view.
Moving an object or scaling an object, or changing the shade of an object can all be represented as a set of
matrix transformations. By changing this matrix in the call back of the animation you will render the object
at a different place with a different scale or a diferent color.
So at a general level, tweening animation is acomplished by changing the properties of a view at various
time intervals during the alloted time of an animation.
Android supports the following types of "tween" animations
AlphaAnimation: Changing Transparency of an object
RotateAnimation: Rotating an object
ScaleAnimation: Scale an object
TranslateAnimation: Move an object
In Android frame by frame animation a series of drawable resources are loaded one after the other. The
class AnimationDrawable is responsible for frame by frame animation. Each frame in this animation is a
drawable resource.
As you get deeper into Android animation you will see that the distinction is not so clearcut where you can
mix both concepts by essentially redrawing the canvas one way or the other.
Important Classes in the Android Animation Repertoire
As we explore through the animation concepts of Android you will touch upon the following classes.
Animation: Animation is the fundamental class that allows you to animate any view. It does this by
providing an overriden method call back at regular intervals that allows you to change the graphical
transformation matrix. Almost every other concept in android depends on this basic idea. Every derived
animation supports the following tags: duration, fillAfter, fillBefore, interpolator, repeatCount, repeatMode,
startOffset, and zAdjustment.
Matrix: Matrix is a class that belong to the graphics package and is responsible for 2D transformations
including depth and perspective. It may be worthwhile to pick up a basic graphics book to read up on the
basic idea of image transformations using linear algebra. It sounds complicated but the idea is quite simple
and you can quickly get to terms with it in a couple of hours of reading inroductory chapters on it.
Interpolator: An Animation then depends on an implementation interpolator class that is responsible for
interpreting the relative magnitude of values at each sampling point of the animation. The interpolator
implementations include AccelerateDecelerateInterpolator, AccelerateInterpolator, CycleInterpolator,
DecelerateInterpolator, and LinearInterpolator.
AccelerateInterpolator: Uses a hyperbolic curve to interpolate amplitude values along the animation curve.
DecelerateInterpolator: The complement of the AccelerateInterpolator.
AccelerateDecelerateInterpolator: The rate of change starts and ends slowly but accelerates through the
middle.
CycleInterpolator: Uses a sinusoidal pattern for a given number of cycles.
LinearInterpolator: Uses a standard linear gradient where the rate of change is constant
AlphaAnimation: Makes use of the same animation framework but instead of using matrices, uses the color
gradient termed "alpha" on the Transformation object to vary. The xml tag for this is "alpha". The children
tags include: fromAlpha and toAlpha. The Alpha values will range from 0 to 1.
RotateAnimation: A specialized Animation that uses rotation on the matrix supplied by the Transformation
object in the animation callback. This is responsible for rotatin in 2 dimensions. This can be specified in
XML. The xml tag for this is "rotate". The children tags are: a) fromDegrees b) toDegrees c) pivotX d)
pivotY
ScaleAnimation: A specialized Animation that uses scale operations on the matrix supplied by the
Transformation object in the animation callback. This is responsible for animating the changes to size of an
object. The xml tag for scaleAnimation is "scale". The children xml tags include: fromXScale, toXScale,
fromYScale, toYScale, pivotX, pivotY.
TranslateAnimation: A specialized Animation that uses movement operations on the matrix supplied by the
Transformation object in the animation callback. This is responsible for moving an object from one place to
another place in an animated fashion. The xml tag for translation animation is "translate". The children xml
tags include: fromXDelta, toXDelta, fromYDelta, toYDelta.
AnimationSet: Represents a group of Animations that should be played together. The transformation of
each individual animation are composed together into a single transform. If AnimationSet sets any
properties that its children also set (for example, duration or fillBefore), the values of AnimationSet override
the child values. The xml attribute for an animation set is "set". The children includes common tags that
belong any animation. An additional binary child "shareInterpolator" is used to indicate if the children should
use the interpolator that is specified at the "set" level.
Camera: Camera is used to provide depth, perspective, or projection to a view. This is familiar concept in
computer graphics. A Camera allows you to construct matrices to suit the needs of a projection of a 2D
image when viewed from a different angle or at a different depth. Camera is used in association with
Tranformation matrix to simulate 3D animations in the 2D space.
LayoutAnimationController: This animation controller is a wrapper for an animation to apply that animation
to the individual objects of a layout, especially to a container of views like a ListView. A LayoutAnimation
controller can be applied to any ViewGroup. Each view of that view group undergoes that animation in a
certain order. A layout animation controller is used to animate a layout's, or a view group's, children. Each
child uses the same animation but for every one of them, the animation starts at a different time.
A layout animation controller is used by ViewGroup to compute the delay by which each child's animation
start must be offset. The delay is computed by using characteristics of each child, like its index in the view
group. This standard implementation computes the delay by multiplying a fixed amount of miliseconds by
the index of the child in its parent view group.
Subclasses are supposed to override getDelayForView(android.view.View) to implement a different way of
computing the delay. For instance, a GridLayoutAnimationController will compute the delay based on the
column and row indices of the child in its parent view group.
The xml tag for a layoutanimationcontroller is "layoutanimation". The children tags include a reference to
the animation tag (animation), the order in which animations are started (animationOrder:normal, random,
or reverse), the amount of delay between each view animation expressed as a fraction (delay), a reference
to the interpolator that interpolates the delay between each animation (interpolator)
GridLayoutAnimationController: This layout animation controller is used to animate a grid layout's children.
While LayoutAnimationController relies only on the index of the child in the view group to compute the
animation delay, this class uses both the X and Y coordinates of the child within a grid. In addition, the
animation direction can be controlled. The default direction is DIRECTION_LEFT_TO_RIGHT |
DIRECTION_TOP_TO_BOTTOM. You can also set the animation priority to columns or rows. The default
priority is none.
The xml tag for GridLayoutAnimationController is "GridLayoutAnimation". In addition to borrowing the
appropriate tags from its parent LayoutAnimationController it has additiona children tags that are:
columnDelay, direction, directionPriority, rowDelay. "columnDelay" is a fraction of the animation duration
used to delay the beginning of the animation of each column. "direction" is the direction of animation in the
grid such as top to bottom or bottom to top, left to right, or right to left etc. "directionPriority" will indicate
animation by column or by row or both.
View: A view is the basic unit of animation. You can attach an Animation object to a view using
setAnimation(Animation) or startAnimation(Animation). The animation can alter the scale, rotation,
translation and alpha of a view over time. If the animation is attached to a view that has children, the
animation will affect the entire subtree rooted by that node. When an animation is started, the framework
will take care of redrawing the appropriate views until the animation completes. The animation related
methods on a view include clearAnimation, startAnimation, setAnimation, getAnimation, onAnimationEnd,
onAnimationStart.
ViewGroup: ViewGroup has a number of animation methods that pertain to animating a group of views.
Some of the animated related methods on a ViewGroup are: clearDisappearingChildren,
getLayoutAnimation, setLayoutAnimation, getLayoutAnimationListener, setLayoutAnimationListener,
isAnimationCacheEnabled(), scheduleLayoutAnimation(), setAnimationCacheEnabled(), and
startLayoutAnimation().
AnimationDrawable: Unlike other animation classes this is part of the graphics package. This class is used
for implementing the frame by frame animation of drawable objects. However it is just a thin wrapper on
top of the animation protocol provided by the Drawable class.
AnimationUtils: Allows you to load animations from xml resource ids.
The role of Transformation Matrices in Animation
The mechanics of animation of are quite simple. Take any scene and if you repaint it quick while some
aspect of that scene is changing you get the impression that something is moving smoothly although the
repaint is happening only with a certain frequency which is typically 24 or 12 frames per second.
what changes at every redraw may be color, position, orientation, or size or any combination of these. If
you want to take a view or a scene or a picture and want to move that scene to the right by a few pixels,
you will typically define a transformation matrix and then apply a matrix multiplication or transformation on
every pixel of the scene to get the new location. So each tranformation is identified by a certain matrix.
If you start with an identity matrix and then apply each transformation to it then you will get a final matrix
that you can apply just one time to transform the view. By changing these matrices in a gradual manner in
a time loop you will accomplish animation. Let's spend a little bit more time and understand the matrix api
before going further.
You can get an identity matrix by doing

import android.graphics.Matrix;
Matrix matrix = new Matrix();
To achieve rotation you can do

matrix.setRotate(degrees)
This method will rotate the view around origin by those many degrees in a 2D space. Some other methods
are

matrix.setScale(x,y);
matrix.setTranslate(x,y);
matrix.setSkew(x,y);
As you call these methods to arrive at a desired matrix be aware of the "set" semantics. "set" semantics
works like a "setting" a variable which means "replace" the current value with the new value. All of these
methods, if you follow the java source code of android eventually resolve to some c++ code from a core
google graphics library called "skia". You can explore the source code online at

http://android.git.kernel.org/
"git" is a source code control system used by the android open source project. You can learn more about
"git" SCM here at

http://git.or.cz/
Now back to understanding of the "set" semantics on these graphics matrices. Let us take a look at the
source code for "setScale":

void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
fMat[kMScaleX] = sx;
fMat[kMScaleY] = sy;
fMat[kMPersp2] = kMatrix22Elem;

fMat[kMTransX] = fMat[kMTransY] =
fMat[kMSkewX] = fMat[kMSkewY] =
fMat[kMPersp0] = fMat[kMPersp1] = 0;

this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
}
The scale function replaces all previous scaling values and pretty much resets the matrix and sets the scale.
So if you have done anything else to the matrix all that is gone. Let us take a look at the "setTranslate" to
see if that is any different.

void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
if (SkScalarAs2sCompliment(dx) | SkScalarAs2sCompliment(dy)) {
fMat[kMTransX] = dx;
fMat[kMTransY] = dy;

fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
fMat[kMSkewX] = fMat[kMSkewY] =
fMat[kMPersp0] = fMat[kMPersp1] = 0;
fMat[kMPersp2] = kMatrix22Elem;

this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
} else {
this->reset();
}
}
Basically sets the scale back to 1 and sets the translations replacing everything before.
So what do you do if you want to apply multiple transformations in a tow. Matrix class provides a set of
"pre*" and "post*" functions for each of the "set*" fucnctions. Let us take a look at the source code for
"preScale"

bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
SkMatrix m;
m.setScale(sx, sy, px, py);
return this->preConcat(m);
}

bool SkMatrix::preConcat(const SkMatrix& mat) {
return this->setConcat(*this, mat);
}

bool SkMatrix::postConcat(const SkMatrix& mat) {
return this->setConcat(mat, *this);
}
Essentially "preScale" creates a brand new matrix with the given scale and then multiplies that matrix with
the current matrix and replaces the current matrix with the resultant matrix. When matrices are multiplied
the order is important. So if we do

m.setScale(..) = rm1
m.preScale(..) = m2 x rm1 = rm3
m.postScale(..) = rm3 x m4 = rm5
I could have acheived the same with

m1.setScale() = m1
m2.setScale() = m2
m3.setScale() = m3

m1.setConcat(m2,m1); // rm3
m1.setConcat(m1,m3); // rm5
You can concat
If "m1" was an identity matrix then the following two would be equal as well

m1.postTranslate(); // take it to the origin
m1.postScale(); //scale it
m1.postTranslate();// take it back to the center

m2.setScale();
m2.preTranslate();
m2.postTranslate();
Then the following is a valid assertion

assert(m1.equals(m2));
Here is some more sample code demonstrating matrix equivalence based on the order of operations on that
matrix

public class TestMatrix
{
public static void test(SomeActivity a)
{
test1(a);
test2(a);
test3(a);
}
public static void test1(SomeActivity a)
{
Matrix m1 = new Matrix();
m1.setScale(2, 2);
m1.preScale(2, 2);
m1.postScale(2, 2);

Matrix m2 = new Matrix();
m2.postScale(2, 2);
m2.postScale(2, 2);
m2.postScale(2, 2);

assertL("test1",a,m1,m2,"m1 and m2 will be same");
}

public static void test2(SomeActivity a)
{
Matrix m1 = new Matrix();
m1.setScale(2, 2);
m1.preTranslate(-2, -2);
m1.postTranslate(2, 2);

Matrix m2 = new Matrix();
m2.postTranslate(-2, -2);
m2.postScale(2, 2);
m2.postTranslate(2, 2);

assertL("test2",a,m1,m2,"m1 and m2 will be the same");
}

public static void test3(SomeActivity a)
{
Matrix m1 = new Matrix();
m1.setScale(2, 2);
m1.preTranslate(-2, -2);
m1.postTranslate(2, 2);

Matrix m2 = new Matrix();
m2.preTranslate(-2, -2);
m2.postTranslate(2, 2);
m2.setScale(2, 2);

assertL("test4",a,m1,m2,"m1 and m2 will not be the same");

Matrix m3 = new Matrix();
m3.setScale(2, 2);
assertL("test3",a,m2,m3,"m2 and m3 will be the same");
}

private static void assertL(String testName
, SomeActivity a
, Matrix m1
, Matrix m2
, String assertText)
{
if (m1.equals(m2))
{
a.appendText("\n" + testName + ": m1 is same as m2");
}
else
{
a.appendText("\n" + testName + ": m1 is NOT same as m2");
}
}
}
In summary all the "pre*" and "post*" methods are mere shortcuts to "setConcat" against itself.

preTranslate(m) -> setConcat(m x self)
preRotate(m) -> setConcat(m x self)
preScale(m) -> setConcat(m x self)
preSkew(m) -> setConcat(m x self)

postTranslate(m) -> setConcat (self x m)
postRotate(m) -> setConcat (self x m)
postScale(m) -> setConcat (self x m)
postSkew(m) -> setConcat (self x m)
Layout Animations
Android has rigged some of the animation concepts into layout containers such as list boxes and grids. As a
result quickest way to see an animation is to prod a layout container to use a predefined animation in an
xml file. The pattern goes as follows
1. Define an animation declaratively in the "anim" sub directory using a file.
2. Android creates an animation id based on the filename for that animation definition
3. Define a spcial case of animation called layout animation which is really a wrapper for the animation
defined in step 1. This file is also created in the same location namely "res/anim"
4. Android creates an animation id for this layout animation file as well
5. Specify the animation "id" in step 4 as an animation attribute to the layout in the layout xml file
let us see an example of this by creating a file called "scale.xml" in the "res/anim" sub directory.

//res/anim/scale.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<scale
android:fromXScale="1"
android:toXScale="1"
android:fromYScale="0.1"
android:toYScale="1.0"
android:duration="500"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="100" />
</set>
This animation keeps the x scale same, but increases the "y" scale from 1/10 of its size to its target size of
"1" (original size). It takes 1/2 a second to reach the target state. It uses mid way point or the center of the
view as its pivot point.
Scale attribute may be a floating point value, such as "1.2". May be a fractional value, which is a
floating point number appended with either % or %p, such as "14.5%". The % suffix always
means a percentage of the base size; the optional %p suffix provides a size relative to some
parent container. The values can be negative as well.
This animation can be applied to any view as a whole. However it needs to be wrapped in a layout
animation tag to be allowed for a layout container. The layout animation declaration allows additional
attributes that talk about the collection of items the container manages. Here is an example that uses the
above basic animation:

//res/anim/scale_container_elements.xml
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="30%"
android:animationOrder="reverse"
android:animation="@anim/scale" />
As it has been pointed out LayoutAnimation is just a thin wrapper on top of the basic animation. The "30%"
delay says that apply the underlying animation after a delay for each contained view. Do the animation in
reverse order of items listed in the container. The only remaining attribute of a layout animation that is not
listed above is "android:interpolator".
Android defines a set of predefined interpolators. These are

android:interpolator=@anim/accelerate_decelerate_interpolator
android:interpolator=@anim/accelerate_interpolator
android:interpolator=@anim/decelerate_interpolator
Each of these definitions are essentially xml files in the base android package under the "res/anim" sub
directory.
res/anim/decelerateInterpolator.xml

<decelerateInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"
factor="1" />
res/anim/accelerateInterpolator.xml

<accelerateInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"
factor="1" />
res/anim/accelerateDecelerateInterpolator.xml

<accelerateDecelerateInterpolator
xmlns:android="http://schemas.android.com/apk/res/android"/>
Lets talk about interpolators for a minute. An interpolator defines the rate of change in an animation. This
allows the basic animation effects (alpha, scale, translate, rotate) to be accelerated, decelerated, repeated,
etc, sometimes in a particular pattern. An interpolator is used to pass a factor between 0 and 1 to the
animation callback through the parameter "interpolatedTime" to the following applyTransformation call back
of an Animation object.

@Override
protected void applyTransformation(float interpolatedTime
,Transformation t)
{
}
The value of "0" for interpolatedTime indicates the start of the animation and the value of "1" indicates the
end of animation. One will use this as a multiplication factor to modulate the characteristic that is being
animated: be it position or scale or rotation.
Some of the builtin interpolators are
AccelerateDecelerateInterpolator: An interpolator where the rate of change starts and ends slowly but
accelerates through the middle. It doesnt have any additional parameters to change the behavior other than
what was built into it.
AccelerateInterpolator: An interpolator where the rate of change starts out slowly and and then
accelerates. It can take an additional argument called "factor". This argument controls the degree to which
the animation should be eased. Seting factor to 1.0f produces a y=x^2 parabola. Increasing factor above
1.0f exaggerates the ease-in effect (i.e., it starts even slower and ends evens faster)
Here is the source code snippet of how "factor" is used

public float getInterpolation(float input)
{
if (mFactor == 1.0f)
{
return (float)(input * input);
}
else
{
return (float)Math.pow(input, 2 * mFactor);
}
}
By default "mFactor" is 1.
CycleInterpolator: Repeats the animation for a specified number of cycles. The rate of change follows a
sinusoidal pattern.
DecelerateInterpolator: It is the opposite of AccelerateInterpolator. It uses the factor the same way but
in the opposite direction.
LinearInterpolator: This interpolatro keeps the rate of change constant.
GridLayoutAnimation
LayoutAnimation is typically used for linear lists where there is no concept of rows and columns. For those
containers like a grid where there are rows and columns there is a variation on the layoutanimation tag
called "GridLayoutAnimation". This tag allows the following additional xml tags as children:
columnDelay: Fraction of the animation duration used to delay the begining of animation for each column.
The value is a percentage value.
direction : One of a) left_to_right b) right_to_left c) top_to_bottom d) bottom_to_top
directionPriority: One of a) none b) column c) row. For "none" both columns and rows are animated at
the same time. For "Column" columns are animated first. For "row" rows are animated first.
rowDelay: Fraction of the animation duration used to delay the begining of animation for each column. The
value is a percentage value.
Both these animations are also available to the java programmers as

LayoutAnimationController
GridLayoutAnimationController
Same level of flexibility is allowed for both these java objects.
Tieing a layout animation to a list control
Let us return to the main line story where we are trying to tie the layout aninmation to a list view. so far we
have
1. A basic animation defined in "res/anim/scale.xml"
2. A layout animation that wrapped the basic animation in "res/anim/scale_container_elements.xml"
Let us now look at an xml file for a possible activity. Call this xml file "test_animations_layout.xml"

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<ListView
android:id="@android:id/list"
android:persistentDrawingCache="animation|scrolling"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layoutAnimation="@anim/scale_container_elements" />

<ImageView
android:id="@+id/picture"
android:scaleType="fitCenter"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone" />

</FrameLayout>
The frame layout in this example is holding two views. A list view that we will use to point to a list of photo
image names and then an image view that will contain the picture of a selected image from the list. Notice
how the layout animation attribute is pointing to a scale animation through a layout animation wrapper.
Here is a segment of code that can be used to initialize an activity

//Set the activity layout first
setContentView(R.layout.test_animations_layout);

//get the list view
mPhotoListView = (ListView) findViewById(android.R.id.list);

//get an adapter
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(this
,android.R.layout.simple_list_item_1
,PHOTOS_NAMES);

//Notice how it uses a predefined view
//for the list item

//Attach the adapter to the list
mPhotosListView.setAdapter(adapter);
Notice how the list view needs to be supplied with an adapter to populate the rows of the list. This is done
through an adapter. Let us see how one can define an array adapter using an array of strings.

private static final
String[] PHOTOS_NAMES = new String[] {
"Lyon",
"Livermore",
"Tahoe Pier",
"Lake Tahoe",
"Grand Canyon",
"Bodie"
};

// Resource identifiers for the photos we want to display
private static final int[] PHOTOS_RESOURCES = new int[] {
R.drawable.photo1,
R.drawable.photo2,
R.drawable.photo3,
R.drawable.photo4,
R.drawable.photo5,
R.drawable.photo6
};

This array of strings will become titles for each list item. The adapter also needs the layout view for
displaying each item. Although the view for a list item is defined by the "ListView" tag, the view for each list
item is controlled by its adapter. Android defines a number of predefined views for these list items. Some of
these predefined views include:

simple_list_item_1
simple_list_item_2
simple_list_item_checked
simple_list_item_multiple_choice
simple_list_item_single_choice
The code so far is sufficient to test the scaling animation. When this code is executed you will see that the
items in the list box will start out really small and gradually grow to their original size on the "y" axis.
Essentially the strings are scaled vertically while keeping their horizontal sizing constant. Now you can
change the "scale.xml" to include a variety of animations and see how they effect the list animation. Here
are some example animations you can try:
Moving the text items from left to right

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate android:fromXDelta="-100%p"
android:toXDelta="0"
android:duration="150" />
</set>
This is a "translate" animation that moves the object from 100% of the parent size starting off the screen
and move to the right and stopping at an "x" value of 0. This has the effect of text sliding to the right and
stopping when the left side of the text aligns on the left side with the container.
Just for experimentation you can replace the scale animation in this example with any of the following
animations to see how they appear in action. Here are some examples that cover fading, movement, and
rotation
An example of fading using "alpha" animation

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="100" />
Here is how you can move on the Y axis and also fade at the same time

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate android:fromYDelta="-100%" android:toYDelta="0"
android:duration="100" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="50"
/>
</set>
Here is an example of rotating the list item at its mid point from 0 to 360 degrees.

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromDegrees="0.0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="100" />
Animating a View as a whole programmatically
So far we have hinted at animating a view using matrices and pointed out that the built in animations like
Translate and Scale or just special cases of animating a view with the base class "Animation". We have also
showed you how these built in animations can be quickly attached to containers such as list boxes and
grids. In the example above we have a ListView that is capable of animating its children. Now we would like
to show you how you can animate the ListView itself as a whole. As an added bit of complexity we will
rotate the ListView in the "z" axis to the point where it completely disappears when it is turned 90 degrees
into the "z" axis.
So we are going to be talking about two concepts. Writing your own animation and then animating
something in the third dimension. The android.graphics package which hosts most of these concepts is
essentially a 2D package and hence won't allow for a 3D rotation directly through the matirx
transformation. Instead it provides an object called "Camera" that applies a perspective view on a 2D object
when it is looked from a certain angle including depth perception. So in this example we will also cover the
Camera object and how to use it.
This chapter heavily borrows from the animation example provided in the "ApiDemos" but at the same time
adds a lot of basic information required to understand that example. In the end you would have covered
many of the 2D animation apis in android. This animation example in the api demos essentially does the
following. It shows how to tie layout animation to a list box. We have covered this already. At the end of
that lay out animation you will see a list of image names displayed in a list box. Once you click on one of
the image names, the whole frame will rotate 90 degrees as if in 3D space and the corresponding image for
that name will swing in to view using the same animation but in reverse. When you are looking at that
image as you click on it, the image will rotate 90 degrees in 3D and disappear and the image name list will
appear in reverse animation.
In the process of understanding this exercise you will learn
1. How to write your own animation
2. How to apply 3D like transforms using a Camera object
3. You will know how to apply what you have learned about matrix transformations
4. You will learn about animation call backs and how to use "post" to invoke actions
Creating a specialized Transformation
The structure for specializing an animation is quite simple. You will initialize the rotation with some
dimensions both for the object in question and also its parent. then you will override the "often" called
applyTranformation. This method is called to simulate the animation using an interpolated time parameter
that changes from its initial value to the target value at the end of the animation. The second parameter to
this method the "Transformation" essentially is a wrapper to the transformation matrix. Here is the skeleton
code for this:

public class Rotate3dAnimation extends Animation
{
public Rotate3dAnimation(....){}

@Override
public void initialize(int width, int height,
int parentWidth, int parentHeight)
{
super.initialize(width, height, parentWidth, parentHeight);
....your stuff
}

@Override
protected void applyTransformation(float interpolatedTime
,Transformation t)
{
}
}
To reemphasize the simplicity of this idea lets take a quick look at the built-in TranslateAnimation class

public class TranslateAnimation extends Animation {
private int mFromXType = ABSOLUTE;
private int mToXType = ABSOLUTE;

private int mFromYType = ABSOLUTE;
private int mToYType = ABSOLUTE;

private float mFromXValue = 0.0f;
private float mToXValue = 0.0f;

private float mFromYValue = 0.0f;
private float mToYValue = 0.0f;

private float mFromXDelta;
private float mToXDelta;
private float mFromYDelta;
private float mToYDelta;

public TranslateAnimation(float fromXDelta, float toXDelta,
float fromYDelta, float toYDelta) {
mFromXValue = fromXDelta;
mToXValue = toXDelta;
mFromYValue = fromYDelta;
mToYValue = toYDelta;

mFromXType = ABSOLUTE;
mToXType = ABSOLUTE;
mFromYType = ABSOLUTE;
mToYType = ABSOLUTE;
}

*/
public TranslateAnimation(int fromXType, float fromXValue,
int toXType, float toXValue,
int fromYType, float fromYValue, int toYType, float toYValue)
{
mFromXValue = fromXValue;
mToXValue = toXValue;
mFromYValue = fromYValue;
mToYValue = toYValue;

mFromXType = fromXType;
mToXType = toXType;
mFromYType = fromYType;
mToYType = toYType;
}


@Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
float dx = mFromXDelta;
float dy = mFromYDelta;
if (mFromXDelta != mToXDelta) {
dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
}
if (mFromYDelta != mToYDelta) {
dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
}

t.getMatrix().setTranslate(dx, dy);
}

@Override
public void initialize(int width, int height, int parentWidth, int
parentHeight)
{
super.initialize(width, height, parentWidth, parentHeight);
mFromXDelta = resolveSize(mFromXType, mFromXValue, width, parentWidth);
mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
mFromYDelta = resolveSize(mFromYType, mFromYValue, height,
parentHeight);
mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
}
}
Using Matrices and Camera for rotating in 3D on a 2D surface
With the background so far let us examine how we can accomplish 3D like transformation with a set of 2D
tools. Let us examine the following code from the api demos closely. we first figure out the amount of
degrees to rotate based on the interpolated time. That is straight forward. We then use a "Camera" object.
A "Camera" object is provided so that it can manipulate the perspective in a matrix and then give us the
resulting matrix. So we start with an empty camera object and then ask the camera to go through a depth
perception followed by a rotation on the "Y" axis around the origin. The origin is the left top of a view. Once
the rotation on the "Y" axis is complete we get the matrix back from the camera and super impose on the
matrix that was gotten from the "Transformation" object. Once the matrix is super imposed we set the
Camera back to its original state to reuse it again in the next tranformation cycle.

protected void applyTransformation(float interpolatedTime,
Transformation t)
{
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees +
((mToDegrees - fromDegrees) * interpolatedTime);

final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;

final Matrix matrix = t.getMatrix();

camera.save();
if (mReverse) {
camera.translate(0.0f, 0.0f,
mDepthZ * interpolatedTime);
} else {
camera.translate(0.0f, 0.0f,
mDepthZ * (1.0f - interpolatedTime));
}
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();

matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
Before we let go of the method we move the view to the origin and then allow the "Camera" transformation
and then move it back to its original position. This is often represented by the following pattern

matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
These two methods are equivalent to moving a view to the center of the 2D geometry and then move back
to their original center. This is necessary because the Camera translations did not take a "pivot" point and
assume a translation around the origin. With out the "pretranslation" you will see the object move like a fan
around the "y" axis instead of a "spin" like motion. Just for your complete understanding you should
comment out one of these lines and observe the behavior.
It is also important to note that the rotations on a Camera allows an axis specification where as the Matrix
rotations don't specify an axis and assume a 2D world. That is essentially the point of a Camera object.
Let us take a quick look at the methods available on a Camera object.

translate(x,y,z)
rotateX(degrees)
rotateY(degrees)
rotateZ(degrees)
So fundamentally a Camera can translate a view in the third dimension by giving it a perspective (Projection
in 2D) and then allows you the same interms of rotation across any axis.
Making 3D rotation a reusable animation object
Here is the constructor of the 3D rotation animation that any code can use to construct

public Rotate3dAnimation(float fromDegrees, float toDegrees,
float centerX, float centerY,
float depthZ, boolean reverse)
The from and to degrees allow how much rotation around the center of "x" and "y" at how much depth and
if the rotation should be in reverse.
Here is an example of how this object is constructed and used in the demo appplication

private void applyRotation(View view, int position,
float startAngle, float endAngle)
{
// Find the center of the container
final float centerX = view.getWidth() / 2.0f;
final float centerY = view.getHeight() / 2.0f;

// Create a new 3D rotation with the supplied parameter
// The animation listener is used to trigger the next animation
final Rotate3dAnimation rotation =
new Rotate3dAnimation(startAngle, endAngle, centerX,
centerY, 310.0f, true);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());

rotation.setAnimationListener(new DisplayNextView(position));

view.startAnimation(rotation);
}
Here are two places where this applyRotation is called

applyRotation(someView, position, 0, 90);
applyRotation(someView, -1, 180, 90);
Coding Animation Callbacks
The variable "position" is unrelated to animation and it is used here to know which item in the list box is
selected. Depending on the item that is selected a new image corresponding to that position is brought into
view using the 3D animation. Another notable takeaway from the above code is how a call back is registered
when the animation completes. Let us take a look at that code as that will demonstrate how animation call
backs are used

private final class DisplayNextView implements Animation.AnimationListener {
private final int mPosition;

private DisplayNextView(int position) {
mPosition = position;
}

public void onAnimationStart(Animation animation) {
}

public void onAnimationEnd(Animation animation) {
mContainer.post(new SwapViews(mPosition));
}

public void onAnimationRepeat(Animation animation) {
}
}
Once again in the call back the necessary action is deferred and invoked using a post back so that it can be
executed on the main UI thread and allowing the animation to come to a conclusion. Let us see how that
call back code looks like:

private final class SwapViews implements Runnable {
private final int mPosition;

public SwapViews(int position) {
mPosition = position;
}

public void run() {
final float centerX = mContainer.getWidth() / 2.0f;
final float centerY = mContainer.getHeight() / 2.0f;
Rotate3dAnimation rotation;

if (mPosition > -1) {
mPhotosList.setVisibility(View.GONE);
mImageView.setVisibility(View.VISIBLE);
mImageView.requestFocus();

rotation = new Rotate3dAnimation(90, 180, centerX, centerY, 310.0f,
false);
} else {
mImageView.setVisibility(View.GONE);
mPhotosList.setVisibility(View.VISIBLE);
mPhotosList.requestFocus();

rotation = new Rotate3dAnimation(90, 0, centerX, centerY, 310.0f,
false);
}

rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new DecelerateInterpolator());

mContainer.startAnimation(rotation);
}
}
The key to note is that the call back for a "post" method is a Runnable object with a "run" method. In this
case it sets the visible component of a FrameView from the list to the individual image and vice versa. And
for that reason the class is called "swapviews". A framelayout essentially allows visibility to one view at a
time. Once the views are swapped it applies 3D rotation on those views.
Starting Animation
We now know how to swap the views between list view and the image view at the end of an animation. Let
us see now how we respond to the mouse clicks on these views. For example the mouse click on a list item
should trigger an animation to show the image. A mouse click on the image should trigger an animation to
show the list view. Here are these two call back functions:

public class Transition3d extends Activity implements
AdapterView.OnItemClickListener, View.OnClickListener
{
.....
public void onItemClick(AdapterView parent, View v, int position, long id)
{
// Pre-load the image then start the animation
mImageView.setImageResource(PHOTOS_RESOURCES[position]);
applyRotation(position, 0, 90);
}

public void onClick(View v) {
applyRotation(-1, 180, 90);
}
....
}
Notice how we have to implement two kinds of callbacks. One on the AdapterView and another on a View.
See how each call back is reusing the common applyRotation function.
Example XML demonstrating animation
It should be clear by now that crafting your own animations is simply a matter of changing the
transformation matrix in the animation call back on a view. It should be no surprise that all of the built in
animations are constructed this way. Here is the relevent source code for some of these built in animations:
Rotate Animation

@Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) *
interpolatedTime);

if (mPivotX == 0.0f && mPivotY == 0.0f) {
t.getMatrix().setRotate(degrees);
} else {
t.getMatrix().setRotate(degrees, mPivotX, mPivotY);
}
}
Scale Animation

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float sx = 1.0f;
float sy = 1.0f;

if (mFromX != 1.0f || mToX != 1.0f) {
sx = mFromX + ((mToX - mFromX) * interpolatedTime);
}
if (mFromY != 1.0f || mToY != 1.0f) {
sy = mFromY + ((mToY - mFromY) * interpolatedTime);
}

if (mPivotX == 0 && mPivotY == 0) {
t.getMatrix().setScale(sx, sy);
} else {
t.getMatrix().setScale(sx, sy, mPivotX, mPivotY);
}
}
Alpha Animation

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float alpha = mFromAlpha;
t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
}
The simplicity of this approach should give us confidance to craft our own animations quite easily. Let us
now turn our attention to more practical matters and take in some sample animation XML files so that we
could quickly use these XML animation patterns in our own code. These examples are borrowed from
Android documentation

<set android:shareInterpolator="true"
android:interpolator="@android:anim/accelerate_interpolator">

<translate android:fromXDelta="0"
android:toXDelta="30"
android:duration="800"
android:fillAfter="true"/>

<set android:duration="800"
android:pivotX="50%"
android:pivotY="50%" >

<rotate android:fromDegrees="0"
android:toDegrees="-90"
android:fillAfter="true"
android:startOffset="800"/>

<scale android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="2.0"
android:startOffset="800" />
</set>

<translate android:toYDelta="-100"
android:fillAfter="true"
android:duration="800"
android:startOffset="1600"/>
</set>
Example Java code
Equivalent java code for the same is

// Create root AnimationSet.
AnimationSet rootSet = new AnimationSet(true);
rootSet.setInterpolator(new AccelerateInterpolator());
rootSet.setRepeatMode(Animation.NO_REPEAT);

// Create and add first child, a motion animation.
TranslateAnimation trans1 = new TranslateAnimation(0, 30, 0, 0);
trans1.setStartOffset(0);
trans1.setDuration(800);
trans1.setFillAfter(true);
rootSet.addAnimation(trans1);

// Create a rotate and a size animation.
RotateAnimation rotate = new RotateAnimation(
0,
-90,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotate.setFillAfter(true);
rotate.setDuration(800);

ScaleAnimation scale = new ScaleAnimation(
1, 2, 1, 2, // From x, to x, from y, to y
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
scale.setDuration(800);
scale.setFillAfter(true);

// Add rotate and size animations to a new set,
// then add the set to the root set.
AnimationSet childSet = new AnimationSet(true);
childSet.setStartOffset(800);
childSet.addAnimation(rotate);
childSet.addAnimation(scale);
rootSet.addAnimation(childSet);

// Add a final motion animation to the root set.
TranslateAnimation trans2 = new TranslateAnimation(0, 0, 0, -100);
trans2.setFillAfter(true);
trans2.setDuration(800);
trans2.setStartOffset(1600);
rootSet.addAnimation(trans2);

// Start the animation.
animWindow.startAnimation(rootSet);
Standard Animation Attributes
android:startOffset: The start time (in milliseconds) of a transformation, where 0 is the start time of the
root animation set.
android:duration: The duration (in milliseconds) of a transformation.
android:fillafter: Whether you want the transform you apply to continue after the duration of the
transformation has expired. If false, the original value will immediately be applied when the transformation
is done. So, for example, if you want to make a dot move down, then right in an "L" shape, if this value is
not true, at the end of the down motion the text box will immediately jump back to the top before moving
right.
android:fillBefore: True if you want this transformation to be applied at time zero, regardless of your start
time value (you will probably never need this).
Dimensions in Android
Consider the following translate animation XML specification

<translate android:fromXDelta="-100%p"
android:toXDelta="2"
android:duration="3000"
android:fillAfter="true"/>
One will wonder what is allowed as a dimension in the "toXDelta". Currently it has "2". What is 2? Is it one
of the following dimensions that are allowed in Android:
px - pixels on the screen
in - inches
mm - millimeters
pt - points 1/72 of an inch
dp - density independent pixels. Relative to a 160 dpi screen.
sp - Scale-independent Pixels. These are like the dp units, but it are also scaled by the user's font size
preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted for both
the screen density and user's preference.
Examples of dimensions.

<resources>
<dimen name="one_pixel">1px</dimen>
<dimen name="double_density">2dp</dimen>
<dimen name="sixteen_sp">16sp</dimen>
</resources>
As it turns out if you replace "2" with a "2sp" or "2px" you will get a compile time error indicating that
dimension values are not allowed for these attributes. So what are these values then?
These attributes supports values in any of the following three formats: values from -100 to 100, ending with
"%", indicating a percentage relative to itself; values from -100 to 100, ending in "%p", indicating a
percentage relative to its parent; a float with no suffix, indicating an absolute value.
Consider the example below

<translate android:fromXDelta="-100%p"
android:toXDelta="150"
android:duration="1000"
android:fillAfter="true"/>
Meaning: Start at an "X" value that starts at negative 100% of the parent and move to positive 150 pixels
(the left side coordinate of the object) and take 1 sec to do that. For example if what you were animating is
text, then the text will start at right most point and move to the right until the left hand side of the text
moved 150 pixels to the right from the left 0.
A better translation is this

<translate android:fromXDelta="-100%p"
android:toXDelta="0"
android:duration="3000"
android:fillAfter="true"/>
This stops the animation as soon as the left most letter comes into the visibility as the word moves to the
right. Once the animation is complete, the text goes back to its original state of X:0. This would be the
same as the final state of the animation. Otherwise you will see a sudden shift from the final state of the
animation to the natural positioning of the object.
Here is an example of scale animation that scales the text on "Y" axis for 1/10th to its original size over half
a second.

<scale
android:fromXScale="1"
android:toXScale="1"
android:fromYScale="0.1"
android:toYScale="1.0"
android:duration="500"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="100" />
Source code of interpolators
To understand interpolators well and what they do underneath here is the source code of the predefined
interpolators in Android.
LinearInterpolator: Uses a standard linear gradient where the rate of change is constant

public float getInterpolation(float input)
{
return input;
}
CycleInterpolator: Uses a sinusoidal pattern for a given number of cycles.

public CycleInterpolator(float cycles)
{
mCycles = cycles;
}
public float getInterpolation(float input) {
return (float)(Math.sin(2 * mCycles * Math.PI * input));
}
AccelerateInterpolator: Uses a hyperbolic curve to interpolate amplitude values along the animation curve.

public AccelerateInterpolator(float factor) {
mFactor = factor;
}

public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return (float)(input * input);
} else {
return (float)Math.pow(input, 2 * mFactor);
}
}
DecelerateInterpolator: The complement of the AccelerateInterpolator.

public DecelerateInterpolator(float factor) {
mFactor = factor;
}

public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return (float)(1.0f - (1.0f - input) * (1.0f - input));
} else {
return (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
}
}
AccelerateDecelerateInterpolator: The rate of change starts and ends slowly but accelerates through the
middle.

public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
Frame By Frame Animation
Frame By Frame Animation is accomplished through a class in the graphics package called
AnimationDrawable. This class is capable of taking a list of drawable resources and then render them at the
specified intervals. This class is really a thin wrapper to the animation support provided by the basic
Drawable class. Drawable class enables animation by asking its container (or on which it draws such as say
a View) to invoke a runnable class that essentailly redraws the drawable using a different set of parameters.
However these internal implementation details are not necessary to use the AnimationDrawable class. To
use this class start with a set of drawable resources placed in the "res/drawable" sub directory. Here is an
example

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/numbers11" android:duration="50" />
<item android:drawable="@drawable/numbers12" android:duration="50" />
<item android:drawable="@drawable/numbers13" android:duration="50" />
<item android:drawable="@drawable/numbers14" android:duration="50" />
<item android:drawable="@drawable/numbers15" android:duration="50" />
<item android:drawable="@drawable/numbers16" android:duration="50" />
<item android:drawable="@drawable/numbers17" android:duration="50" />
<item android:drawable="@drawable/numbers18" android:duration="50" />
<item android:drawable="@drawable/numbers19" android:duration="50" />
</animation-list>
I have called this file "res/drawable/frame_animation.xml". These are png images that I have created using
a power point. I drew a big circle and then placed a small ball on the perimeter of the circle in 8 places.
Then I saved the images 9 time with each image having the ball at a different place on the circular line. The
goal is to play these images in succession to show as if the ball is moving in a circular orbit.
Here is how I have defined a layout to test this.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="@+id/startFAButtonId"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start Animation"
/>

<ImageView
android:id="@+id/animationImage"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
The layout is basically a button followed by an image view. The image view will be used as the background
for the animation. Let us see how the activity is going to be initialized.

public class FrameAnimationActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.frame_animations_layout);
this.setupButton();
}
....
}
Pretty clear so far. Just initialize the activity and call to setup the button to start the animation. Here is the
code for "setupButton":

private void setupButton()
{
Button b = (Button)this.findViewById(R.id.startFAButtonId);
b.setOnClickListener(
new Button.OnClickListener(){
public void onClick(View v)
{
animateImageView();
}
});
}
The animation is quite simple as well. When you set the background resource of an image using an
"animation_list" drawable it creates an AnimationDrawable and attaches it as the drawable resource of the
background. We get this object and start animation on it. A few important caveats however. For testing this
animation don't set the resource for the image itself. The "z" order seem to mask the animation. Also if you
want to restart the animation after you have started it, you will have to "stop" and then "start". If you allow
the animation to repeat then this is not a concern, clearly. The animation below is coded in such a way that
if you press the button it will start the animation. And if you press the button again it will stop and the
pattern continues between start and stop.

private void animateImageView()
{
// Load the ImageView that will host the animation and
// set its background to our AnimationDrawable XML resource.
ImageView img = (ImageView)findViewById(R.id.animationImage);
img.setBackgroundResource(R.drawable.frame_animation);

// Get the background, which has been compiled to an AnimationDrawable
object.
AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();

// Start the animation (looped playback by default).
if (frameAnimation.isRunning())
{
frameAnimation.stop();
}
else
{
frameAnimation.start();
}
}
Unlike the Animation class this AnimationDrawable class does not provide a callback on the completion of
the animation. For example if you set the "oneshot" parameter of the animation list to "true" then the
animation will stop after doing the animation once. However there is no clearcut way to know that.
There is more to Android animation. The leaf level classes of animation such as those derived from
Animation (ScaleAnimation, TranslateAnimation etc) and those derived from Drawable (AnimationDrawable)
or just the tip of the animation facilities. The core of animation lies in redrawing the canvas using a
combination of these facilities that are outlined here.
Sample Animation Files
Layout animations combined with XML animation definitions provide a powerful way to quickly add visual
effects to Android applications. As you start experimenting with animations it is worthwhile to keep a quick
reference to example animations so that you can copy the code and change the code for your own need. In
that spirit here are some example animations from the android documentation. These will be handy as you
work the animations in Android.
Fade.xml

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="100" />
layout_grid_fade.xml

<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:rowDelay="50%"
android:directionPriority="column"
android:animation="@anim/fade" />
layout_grid_inverse_fade.xml

<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:columnDelay="0.5"
android:directionPriority="row"
android:direction="right_to_left|bottom_to_top"
android:animation="@anim/fade" />
layout_grid_random_fade.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="random"
android:animation="@anim/fade" />
hyperspace_in.xml

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="300" android:startOffset="1200" />
hyperspace_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
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/accelerate_interpolator"
android:startOffset="700">
<scale
android:fromXScale="1.4"
android:toXScale="0.0"
android:fromYScale="0.6"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="400" />
<rotate
android:fromDegrees="0"
android:toDegrees="-45"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="400" />
</set>
</set>
layout_animation_row_left_slide.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="10%"
android:animation="@anim/slide_left" />
layout_animation_row_right_slide.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="10%"
android:animationOrder="reverse"
android:animation="@anim/slide_right" />
layout_animation_table.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="50%"
android:animation="@anim/slide_top_to_bottom" />
layout_animation_bottom_to_top.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="30%"
android:animationOrder="reverse"
android:animation="@anim/slide_right" />
layout_wave_scale.xml

<gridLayoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:rowDelay="75%"
android:columnDelay="0%"
android:directionPriority="none"
android:animation="@anim/wave_scale" />
wave_scale.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="100" />
<scale
android:fromXScale="0.5" android:toXScale="1.5"
android:fromYScale="0.5" android:toYScale="1.5"
android:pivotX="50%" android:pivotY="50%"
android:duration="200" />
<scale
android:fromXScale="1.5" android:toXScale="1.0"
android:fromYScale="1.5" android:toYScale="1.0"
android:pivotX="50%" android:pivotY="50%"
android:startOffset="200"
android:duration="100" />
</set>
push_left_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="100%p" android:toXDelta="0"
android:duration="300"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="300" />
</set>
push_left_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-100%p"
android:duration="300"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="300" />
</set>
push_up_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="100%p" android:toYDelta="0"
android:duration="300"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="300" />
</set>
push_up_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="0" android:toYDelta="-100%p"
android:duration="300"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="300" />
</set>
cycle_7.xml

<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:cycles="7" />
shake.xml

<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0" android:toXDelta="10"
android:duration="1000" android:interpolator="@anim/cycle_7" />
slide_left.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate android:fromXDelta="100%p" android:toXDelta="0"
android:duration="150" />
</set>
slide_right.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate android:fromXDelta="-100%p" android:toXDelta="0"
android:duration="150" />
</set>
slide_top_to_bottom.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate android:fromYDelta="-100%" android:toXDelta="0"
android:duration="100" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="50" />
</set>

Das könnte Ihnen auch gefallen