Pretty RatingBar

May 23, 2010

Android is a great development platform. Numerous built-in components and widgets simplify developer’s life greatly, and Intents are just awesome — in fact, I added sharing of content through Facebook, email and SMS to my application literally with 10 lines of code. Coming from a Java Swing background, I was surprised at how fast I could build pretty complex and functional UIs without writing a bunch of custom components.

However, while there is a plethora of built-in components, the default look and feel of them sometimes leaves much to be desired. Take RatingBar, for example:

Default RatingBar

Default RatingBar

To me, this just looks ugly. So, when I needed to add a review/rating “feature” to my application, I started looking for a way to make it prettier and more appropriate to my application (which is about food). As a long-time Swing developer, I immediately thought about subclassing RatingBar and overriding some methods (where’s my paintComponent()? :) ) — but it turned out there’s an easier way.

Android comes with a “styling” support, which is great, but not really documented enough (you can read a detailed post about Android styles and how to use them in general here). Actually, it’s a must — so please do if you want to continue understanding what’s going on. In a nutshell, styles provide a way to change the look-and-feel of different parts of Android components entirely through XML, while keeping the code and functionality intact. So, with just a few extra lines of XML and a couple of images, your RatingBar could become this:

Cookie RatingBar

Cookie RatingBar

And how do we get there? First, we’ll need a styles.xml file, which describes our custom styles and lives in the values folder:

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<style name="foodRatingBar" parent="@android:style/Widget.RatingBar">
		<item name="android:progressDrawable">@drawable/food_ratingbar_full</item>
		<item name="android:minHeight">48dip</item>
  		<item name="android:maxHeight">48dip</item>
	</style>
</resources>

This creates a new custom style called foodRatingBar which extends Widget.RatingBar style, sets its height to 48 pixels and its progressDrawable to food_rating_bar (RatingBar is just an extension of a ProgressBar, and each “star” in the RatingBar is basically just another “tick” — progressDrawable — in the ProgressBar). progressDrawable documentation is rather lacking, and the only way I figured out which element I needed to style was by looking through Android’s source code (which is a great way to learn things, by the way). It also provides an insight on what should go into the food_rating_bar_full Drawable:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+android:id/background"
          android:drawable="@drawable/food_ratingbar_full_empty" />
    <item android:id="@+android:id/secondaryProgress"
          android:drawable="@drawable/food_ratingbar_full_empty" />
    <item android:id="@+android:id/progress"
          android:drawable="@drawable/food_ratingbar_full_filled" />
</layer-list>

Basically, it lists out different Drawables to use for background (no cookie – food_ratingbar_full_empty) and progress (selected cookie – food_ratingbar_full_filled). These Drawables are selectors which list out the images to be used in different RatingBar selection states. Here’s an example of a filled rating (cookie):

<?xml version="1.0" encoding="utf-8"?>

<!-- This is the rating bar drawable that is used to
show a filled cookie. -->
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true"
          android:state_window_focused="true"
          android:drawable="@drawable/cookie" />

    <item android:state_focused="true"
          android:state_window_focused="true"
          android:drawable="@drawable/cookie" />

    <item android:state_selected="true"
          android:state_window_focused="true"
          android:drawable="@drawable/cookie" />

    <item android:drawable="@drawable/cookie" />

</selector>

I just use one image for all states (and it actually looks decent), but as you can see from the selector, there are four different states possible (@drawable/cookie is finally an actuall cookie png image). And the cool thing here is that RatingBar component will automatically fill in part of the cookie when needed based only on “full” and “empty” images (if you support half ratings, as in my example image).

Finally, it’s time to apply the style to the RatingBar, which is the easiest part — we just add a style attribute to the <RatingBar>:

		<RatingBar 	android:id="@+id/my_rating_bar"
					...
					style="@style/foodRatingBar" />

And that’s it, RatingBar transformation is complete!

One last thing to note is that there are three different types of RatingBar — one interactive, and two read-only (small and large). In order to style the read-only ones, you would need to create another custom style that extends from the appropriate read-only style — for example, for a small one, it would look like this:

	<style name="foodRatingBarSmall" parent="@android:style/Widget.RatingBar.Small">
		<item name="android:progressDrawable">@drawable/food_ratingbar_small</item>
		<item name="android:minHeight">16dip</item>
  		<item name="android:maxHeight">16dip</item>
	</style>

Basically, we’re just extending from a different parent style, and providing different (smaller) images, and in the read-only case, the half “star” image also needs to be provided.

Have Fun!

20 Responses to “Pretty RatingBar”

  1. [...] How to style Android’s RatingBar Great article explaining changing the style of Android’s default ugly rating widget. [...]

  2. [...] Try rolling your own custom RatingBar with your own images instead. Take a look at : Android Fun Pretty RatingBar hope this [...]

  3. Awesome! You did a great job! I always hate to custom widget but reading your article changes my mind.

  4. This really is a very useful post thanks a lot.

  5. hey, nice blog…really like it and added to bookmarks. keep up with good work

  6. Where do you supply the half “star” image for the read only case? If it goes in your food_ratingbar_small drawable xml file, what is the item ID for the half star image?

  7. Nice post!

    It’s just what I was looking for. Thanks for making android development easier.

  8. I find this link really interesting. I´m trying to do a customized rating bar too and i´m following these hints. However, i´ve tryed this tutorial and i can´t do this to function.

    I´ve created styles.xml within directory “values” and wrote what is in this post. I have 2 images “full” and “empty” in drawable-hdpi. You mean i need to create food_ratingbar_full.xml, food_ratingbar_full_empty.xml and food_ratingbar_full_filled.xml in same directory (drawable-hdpi)? And the last two need to be the same, and the only diference is in the image name “full” or “empty” if we´re whitin food_rating_bar_full_filled or food_rating_bar_full_empty?

    I´ve tried this way and it gives me error launching the app. I have a main with only the rating bar line codes disponibilized here…

    I need some help here. Thanks :)

  9. Sorry for late response, got caught up with work… It will go into the food_ratingbar_small, and you’ll need to set three IDs in the layer list:

    @+android:id/background
    @+android:id/secondaryProgress
    @+android:id/progress

    And these would point to drawables that are actual images.

  10. What kind of error are you getting?

  11. Hi, awesome tutorial.

    I have a question. I’ve implemented your article successfully. But for showing the small rating bar i need to set my layout programmatically.

    using the basic style I’ve used this :
    RatingBar rb = new RatingBar(this,null, android.R.attr.ratingBarStyleSmall);

    when i change using the custom style
    RatingBar rb = new RatingBar(this,null, R.style.goldRatingBarSmall);

    The stars wouldn’t show. Do you know how to fix or a workaround for this ?

    Thanks

  12. Hi.. I also found that although the tutorial works fine with 1.6 sdk. When I’m running with 2.1 emulator i found out that the small custom rating bar is not read only, you can change the values.

  13. Woooow…,

    Great tutorial :-)
    Saved me a LOT of work.

  14. Thank you for sharing!

  15. Great article dude.
    It works like a charm.

    Thanks a lot

  16. Nice tutorial dude! thanks a lot :)

    Any idea of how to display each star/cookie different from each other? I mean, if the ratingbar has five stars, could be posible to put five diferent images for each star?

    Thx again!

    Regards.

  17. Hi am new to android..
    thanku so much for posting this tutorial.
    i followed ur tutorial and am able to do my custom rating bar component. the problem am facing is am not able to create a read only component even am using parent=”@android:style/Widget.RatingBar.Small”>
    and
    @+android:id/background
    @+android:id/secondaryProgress
    @+android:id/progress
    are pointing to drawables that are actual images.

  18. Thanks so much for this tutorial! It’s actually the first thing I’m doing with Android, so it’s been a blast implementing this.

    I have run into a problem, and wonder if you’d be able to help. I can’t specify the width of the rating bar for some reason, with my new style. It still has just “5 stars” but each star is equivalent to 4 of my “stars”… Have you seen this or know what I might be doing wrong?

    Thanks again!

  19. Seems like you just need to modify your layout…

  20. Hi
    Was wondering how you would programatically apply this style?I am facing the same problem as mreunionlabs above. Thanks