1/12/2011

Android: Canvas Frame by Frame Animation Tutorial

In this tutorial I will outline how to play an animation on a canvas on Android.
As you may already know, the canvas is the standard way of drawing on Android.
Drawing to a canvas is fairly straightforward.  You typically extend a View class and override the onDraw method.
In this case we will override ImageView for the sake of simplicity.

I will be using Eclipse for this tutorial.
First, create a new Android project with Eclipse.  You can use 1.5 as the target.  I've named the application animationtest.
Also, make sure you create a default activity, I call mine 'DefaultActivity.'
The package name I'll be using is com.solrpg.animationtest.

After you have created your Android project, create a new class named MyAnimationView.  
This class will extend ImageView and we'll do our drawing here.

Now, your view is ready to use.  Because DefaultActivity simply sets the activity layout to R.layout.main we'll need to modify it.
So, open up res/layout/main.xml and remove the TextView entry and replace it with your custom view using this xml: http://github.com/therevoltingx/android_animation_test/blob/master/res/layout/main.xml

Now we're ready to display our animation.  I have prepared a set of png images from a gif.
You can see the original gif here: http://solrpg.com/resources/attacks/2/2.gif
Then I imported them into res/drawables/ naming them shark_0.png shark_1.png shark_2.png and so on.
Where each number is the frame, all together this animation is 16 frames.

Now it's time to go back to MyAnimationView and add our animation code.  Basically, android calls onDraw every time the view needs to be drawn.
Typically this only happens once when the activity view is being set up.
After that, we have to call invalidate() on the view to have Android call onDraw().

First, we have to load the resource drawables into an array of bitmaps which can be drawn on the canvas.
So, we add a loadAnimation() method to MyAnimationView.  This method simply loads the frames from the res/drawables/ folder into a list of bitmaps.
In the example, we load the bitmaps when the default activity is created.
Once all the bitmaps are loaded, the animation is ready to be drawn.

Now, back to our onDraw method.  
First we have two private state variables called mIsPlaying and mStartPlaying.
Every time onDraw is called we check wether either one of these is set and draw the bitmap frame accordingly.
In order to start an animation we simply set mStartPlaying to true and call invalide() to have Android call onDraw().

When an animation is playing the variable mIsPlaying is set to true it checks which frame it has to draw.
In order to know which frame to play we need two variables play_frame and last_tick.
play_frame is set to the frame index of the animation that we're about to draw.
last_tick is set to a system time stamp.  This time stamp is set every time a frame changes.
This lets us calculate how long the current frame has been drawing.  
Once a specified amount of time has passed it increases the play_frame counter and calls invalidate()

Now you're ready to draw the animation.  We add a method called playAnimation() which simply sets mStartPlaying to true, then it calls invalidate().
In the tutorial application I added a button that when pressed calls playAnimation().

That's it!  Drawing an animation this way is fairly easy, I hope someone finds this helpful.