Posted on

Android Animating Custom View


Android Animating Custom View

Hey guys, let’s do some custom view coding today and combine with the most thing I like – animations! What we’re going to code is a progress circle like they have in Google Fit app. The most trivial view to draw, though it would look amazing to animate it. Excited? Let’s get started! 

And the result would look like this

Android Animating Custom View

Custom View

First of all we need to draw a background grey circle. If you’ve never created a custom, it’s very easy. Just extend View and implement at least first two constructors. First is used when you create a view programmatically, second is used when inflating from XML. You can get a nice explanation in here. And that’s it, now you have a custom view, but it doesn’t display anything.

What we going to draw is is one circle on background and arc on top displaying current value. Let’s say we have a milestone to gain some weight, we want to gain extra 10 kg of muscles. We started at 70, goal is 80. Then 70 won’t display any red circle and when gaining, we draw red circle clockwise. 80 kg will draw full red circle. We also want some cool animation to show when you open its screen. Like animating it from 0 to current value, showing you all the great progress you’ve done.  Coming from here we have those attributes:

  • start value
  • current value
  • end value
  • animation time in milliseconds
  • background circle color
  • foreground circle color
  • stroke width

Custom Attributes

We could easily set all the values in the Java class itself and let user no way to modify the appearance of circles and animations, but that’s not the way to go. After we’ve build this awesome view we want to upload it to jCenter so that other people can use it as a library and modify to their desire as much as possible. What I’m going for is something like ProgressBar class, beautiful API for a user, with just one line you make it a horizontal line, set value, etc. Just beautiful design. Let’s try to achieve something like that

Following this guide I declared those seven attributes for our view in attrs.xml

And to setup fields we have this method to call from constructor

Draw Circle

Let’s do some drawing! First of all, how do we draw stuff on Android? Imaging a sheet of parer and a pen. You take a pen and draw stuff.  Simple right? Canvas class is a representation on a paper sheet, Paint is a pen. Although you call draw methods from a canvas, unlike you would expect from Paint. All methods a well-documented and easy to use. We’re going to do everything in onDraw method which gives us a canvas reference. You can read here about when onDraw method is called.

There’re two shapes to draw: grey background circle, colored foreground progress circle. Let’s start with grey one. Draw circle from X, Y (center) with radius and Paint object. Paint determines whether it’s a filled/hollow circle, color, etc.

Colored foreground circle is an arc. It has four boundaries – left, right, top, bottom, start angle, where 0 is 90° clockwise starting from top. That’s why for us to draw from top we set start angle to -90°. Sweep angle is amount in degrees to go from start angle. There’re other parameters which you can play around if you clone this GitHub repo

Animate

Finally let’s get to the most fun. To animate we call onDraw again and again by invalidate(). onDraw() called 60 times per second, about each 16 ms. Coming from here we know how to animate our colored circle.

FPS

I think that you know why it’s called frames per second, because it’s just frames displayed in a row. Pictures by all means, but our eye reads it as a smooth movement. But in order for us to see pictures as an animation, not just changing pictures we need to change them approximately at least every 20 milliseconds. Don’t quote me on that. You can read this article about this interesting topic

Back to animation. Let’s say we started at 70 kg, our goal is 80, currently we’re at 77 kg.

We’re 70% done, which in degrees is

So we want to animate red circle from 0 to 252°. We set it to take 1 second – 1000 ms. And based on knowing that we draw 60 frames per second we can calculate how much each frame (each time onDraw called) we draw our circle further.

We draw an arc from  0° to 252°, it takes 1 second, there’s 60 frames per second which means we draw arc 4.2° more each time. 0, 4.2, 8.4, 12.6… and it would look like a perfect animation.

There’s just one BUT, it’s that we cannot rely on anything to draw perfect 60 fps. If we do and make our animations based on that it could be a problem. If it’s just an Android app, most likely it will be 60 fps, but in gaming you need to consider time from last frame adjust your position. Nobody cares if it’s 20 fps, object should be still in their right position by their speed etc.

Animate Circle

So I decided to go bold and apply those principle from above. Save animation start time, having duration we know the time animation should end. Each time in onDraw check what time it is and based on that draw circle. It looks smoother I gotta say

If you enjoyed this relatively low level stuff, then I suggest you take a look at LibGDX where you have so much fun with drawing different cool stuff. And check second part of this tutorial

Thanks for reading. Check this GitHub repo for source code. Subscribe to my newsletter, share with friends if you think they will benefit and tell me what you think about think kind of stuff in comments!