If you want to add an animation to your app the first thing you think about is to use animated gifs. But when you perform some research on how to use animated gifs in android you will find out that android does not support this file type. Instead android will always just display one static frame of the animation. But android provides two powerful mechanisms which allow developers to create various types of animations. One way is to use tweened animations where you can define transformation operations such as acceleration, alpha, rotation, scaling, position, etc.  on your objects. The other possibility is to use a frame-by-frame mechanism where it’s possible to define different drawable resources and time intervals in which these resources will be displayed. In this blog post I want to give an introduction on how this frame by frame animation can be implemented in android.

If you are interested in the tweened animation mechanism I would suggest that you refer to the blog post at http://stuffthathappens.com/blog/2008/11/13/android-animation-101/ which shows some basic usage of this animation type.

For this blog post I’ve created a small example app which will just play such a frame-by-frame animation in an activity. The animation which I’ve used is the following Newton’s cradle animation.

Animation of Newton's Cradle (animated gif)
As always you can browse or download the source code of the example App at our SVN repository at Google Code (http://code.google.com/p/android-animation-example/) or use svn to check the project out.

Basics of the Frame-by-Frame Animation

Frame-by-Frame animations are created by creating an xml description file of the animation in your drawable folder. This xml animation can then be accessed in your code like any other drawable. So it’s possible to add such a drawable as a background for an image view. If the animation drawable is added as a background resource android handles the inflating of the animation and this animation object (android.graphics.drawable.AnimationDrawable) can later be accessed with the help of the getBackground method.

It’s also possible to create frame-by-frame animations at runtime using the AnimationDrawable class directly. This class provides a method which can be used to add frames:

  • addFrame(Drawable frame, int duration)

In the following example I will use an xml definition of the animation and not the programmatically way of adding frames.

The AnimationDrawable class also provides methods which can be used to control the animation. For this purpose several methods can be used:

  • void setOneShot(boolean oneShot)

    This method tells the AnimationDrawable if the animation should be repeated (oneShot = false) or if it should only be played once (oneShot = true)

  • void start()

    With the help of this method it is possible to start the animation playback. The animation will be played in a repetitive way if it was previously set (with the help of setOneShot(false)  method)

    This method should not be confused with the “public void run ()” method because the run method should not be called directly.

  • void stop()

    This method can be used to stop the animation playback.

Defining a Frame-by-Frame Animation as a XML Drawable

For defining frame-by-frame animation drawables we have to create an xml file within the drawable folder of the project. The corresponding root tag for this kind of animations is the animation-list tag. This element provides the parameter android:oneshot which is similar to the setOneShot method and defines if the animation should be repeated (false) or not (true). Within this root animation-list element there can be multiple entries of item elements which represent one frame in the animation and have two main parameters android:drawable and android:duration. The android:drawable parameter is used to define a reference to the drawable which will be used for this frame and the android:duration parameter will define how long this frame will be displayed in milliseconds.

In our example I’ve used the Newton’s cradle animation (gif) and extracted the frames of this animation (you can do this for example with the help of GIMP). The result of this extraction are 36 frame images which are named frame0.jpg up to frame35.jpg. These frames are used in the animation.xml file within the drawable folder to create the required animation:

<?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/frame0" android:duration="50" />
	<item android:drawable="@drawable/frame1" android:duration="50" />
	<item android:drawable="@drawable/frame2" android:duration="50" />
	<item android:drawable="@drawable/frame3" android:duration="50" />

	...

	<item android:drawable="@drawable/frame35" android:duration="50" />

</animation-list>

Using a Frame-by-Frame Animation in an Activity

Now that we have defined the animation we can use it in our example activity. The layout of the activity provides an ImageView with the id imageAnimation which will be used to display the animation in the activity:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#E6E6E6">
	<ImageView android:layout_height="wrap_content"
	android:layout_width="wrap_content" android:id="@+id/imageAnimation"
	android:adjustViewBounds="true" />
	</LinearLayout>

Within the activity code there are two locations where we have to take care of the animation. The first is during the onCreate method. Within this method we will set the layout to the corresponding xml layout and then set the background resource of the imageAnimation ImageView to our frame-by-frame animation. Furthermore we will store the reference to the ImageView because we will need it later on to actually start the animation:

public class Animation extends Activity {

	ImageView animation;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		animation = (ImageView)findViewById(R.id.imageAnimation);

		animation.setBackgroundResource(R.drawable.animation);
	}

You might think that we should also start the animation during the onCreate method but that’s not possible. If we call the start method during the onCreate method call android won’t start the animation. This also applies to the onResume method. Other tutorials might advise you to use a timer during this method calls which will start the animation after some delay but this approach is problematic because if the delay is too short the animation won’t start again and if it’s too long the user experience will drop. Furthermore the delay is device specific so on a fast device the delay might be perfectly chosen but when a user with an older and slower device uses the activity the animation won’t start.

To actually start the animation the best choice is the onWindowFocusChanged method. In the android API reference this method is described with “Called when the current Window of the activity gains or loses focus. This is the best indicator of whether this activity is visible to the user.”. As you can imagine it is sufficient that the animation is getting started when the activity is actually visible to the user and not before that. Furthermore this method can be used to stop the animation (to free resources) if the activity is not visible to the user anymore. To get a reference to the animation we use the getBackground method of the ImageView which is an AnimationDrawable because we previously set the background resource to an animation. In the next step we distinguish between if the Activiy is visible (hasFocus = true) or invisible and start or stop the animation correspondingly. In our example the corresponding method is implemented as follows:

	@Override
	public void onWindowFocusChanged (boolean hasFocus) {
		super.onWindowFocusChanged(hasFocus);
		AnimationDrawable frameAnimation = 
			(AnimationDrawable) animation.getBackground();
		if(hasFocus) {
			frameAnimation.start();
		} else {
			frameAnimation.stop();
		}
	}
}

Now everything is implemented and the animation will be played whenever the activity is visible to the user.

by Kevin Kratzer