Creating a Speedometer with drawables and some tricks

There’s a some libs out there that do a great job creating speedometers (a lot better than the one in this article) like SpeedView, but it wasn’t fulfilling the need I had to do with a gradient speedometer that fills itself until a specific point. So with some drawables (and some visibility tricks) I was able to create this:

I’m pretty sure what I’m going to write here is not the best way to do this but it was a nice way for myself to learn a bit more about drawables and how to combine then to create something.

The final project is available at GitHub in the following repository. Feel free to take a look:

The following drawable is the one we will be creating. It is empty in this form. The trick here is to set the color of the drawables that will be at background (white in this case) the same color as your view background where you’re placing the speedometer. If you don’t have a solid background color, sorry, this will not work for you (i’m open to suggestions here!).

First of all, I created 2 half circles that will have the purpose to mark the desired value in the speedometer. One is the gradient fill and the top margin and the black one will serve as a pointer for our speedometer. Here’s the code from both drawables:

This next drawable has the same form as the previous one, but some different measures. It will serve as the black divider in the speedometer:

Now we create another two drawables, one will be the “fake empty gauge” and the other one will be the “transparent” half circle at bottom of the drawable.

They both look the same, the only thing that changes are the sizes:

With all drawables created, it’s time to create a layer-list with all drawables on top of each other and let the magic happens. We are going to use the drawables in that order:

  1. Gradient background
  2. Pointer (the black half circle)
  3. Fake empty background (white one)
  4. Divider (also black)
  5. Fake transparent bottom (also white)

So, what’s really happening here? The pointer and the fake transparent background are actually circles with the top half colored and the bottom half transparent. We are going to rotate then over the gradient background. When this happens, the transparent side will reveal the gradient background and make is looks like its filling itself. Quite clever isn’t it?

The final final drawable:

And it xml file:

Now we just need to add your drawable to your view and make it rotate as necessary.

Just add it as a ImageView and set your layer-list drawable as the background, like this:

Now we just need to rotate our drawables. For that we are going to use a property called “level”. I made a helper class that will take care of the rotation and some safe validation of our speedometer:

Now we just call our helper in our activity passing our layer-list, our ImageView and the values we desire, like this:

And it’s done! We made it! Look:

I need to study a lot more about drawables, as I’m quite sure that there’s some better ways to achieve the same result but I did the way I found out and with some work and some tricks I got the result I wanted.