Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Let Them See Stars: Using RatingBar

Author: Ian Darwin
Published? true
FormatLanguage: WikiFormat

Problem:

You want the user to choose from a number of identical GUI elements in a group to indicate a value such as a "rating" or "evaluation"

Solution:

Use the RatingBar widget; it lets you specify the number of stars to appear, the default rating, be notified when the user changes the value, and retrieve the rating.

Discussion:

RatingBar provides the newly-familiar "Rating" user interface experience, where a user is asked to rank or rate something by a number of stars (the RatingBar doesn't display the thing to be rated; that's up to the rest of your app). RatingBar is a subclass of ProgressBar, extended to display a whole number of icons ("the star") in the bar. Its primary properties are:

  • numStars - the number of stars to display (int)
  • rating - the user's chosen rating (float, because of stepSize)
  • stepSize - the increment for selection (float, common values are 1.0 and 0.5, depending on how fine-grained you want the rating to be).
  • isIndicator - boolean, set to true to make this read-only

These are normally set in the XML:

<RatingBar
    android:id="@+id/serviceBar"
    android:gravity="center"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:numStars="5"
    android:rating="3"
    android:stepSize="1.0"
    android:isIndicator='false'
    />

The RatingBar maintains its rating value internally. You can find out how the user has rated the item in two ways:

  • invoke the getRating() method, or
  • provide a change notification listener of type OnRatingBarChangeListener.

The OnRatingBarChangeListener has a single method, onRatingChanged, called with three arguments:

  • RatingBar rBar - the event source, a reference to the particular RatingBar;
  • float fRating - the rating that was set;
  • boolean fromUser - true if set by a user, false if set programmatically

The example program simulates a Customer Survey; it creates two RatingBars, one to rate Service and another to rate Price (the XML for both is identical except for the android:id). In the main program, an OnRatingBarChangeListener is created, to display touchy-feely--sounding feedback for the given rating (the rating is converted to int and a switch statement is used to generate a message for Toast).

public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        OnRatingBarChangeListener barChangeListener = new OnRatingBarChangeListener() {			
			@Override
			public void onRatingChanged(RatingBar rBar, float fRating, boolean fromUser) {
				int rating = (int) fRating;
				String message = null;
				switch(rating) {
				case 1: message = "Sorry you're really upset with us"; break;
				case 2: message = "Sorry you're not happy"; break;
				case 3: message = "Good enough is not good enough"; break;
				case 4: message = "Thanks, we're glad you liked it."; break;
				case 5: message = "Awesome - thanks!"; break;
				}
				Toast.makeText(Main.this, 
					message,
					Toast.LENGTH_LONG).show();
			}
		};
		final RatingBar sBar = (RatingBar) findViewById(R.id.serviceBar);
		sBar.setOnRatingBarChangeListener(barChangeListener);
		final RatingBar pBar = (RatingBar) findViewById(R.id.priceBar);
		pBar.setOnRatingBarChangeListener(barChangeListener);
        
        Button doneButton = (Button) findViewById(R.id.doneButton);
        doneButton.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				String message = String.format(
						"Final Answer: Price %.0f/%d, Service %.0f/%d%nThank you!",
						sBar.getRating(), sBar.getNumStars(),
						pBar.getRating(), pBar.getNumStars()
						);
				// Thank the user
				Toast.makeText(Main.this, 
						message,
						Toast.LENGTH_LONG).show();
				// And upload the numbers to a database, hopefully...
				
				// That's all for this Activity, hence this App.
				finish();
			}
		});
    }
}

Since there is more than one RatingBar, we don't save the value in the listener, since an incomplete survey is not useful in our scenario; in the Done Button action listener, we fetch both values, display them, and this would be the place to save them. Your mileage may vary: it may make more sense to save them in the OnRatingBarChangeListener.

If you're not used to printf-like formatting, the String.format call uses %.0f to format the float as an int, instead of casting it (since we have to do nice formatting anyway). Ideally the format message should be from the XML strings, but it's only a demo program.

The main UI looks like this: displaying a feedback rating:

.

When the user clicks the Done button, they will see the Farewell message displayed on the desktop window:

XXX TODO - discuss behavior with fractional increment!

When you wish both to display the current "average" or similar measure ratings from a community and allow the user to enter their own rating, it is customary to display the current ratings read-only, and to create a pop-up dialog to enter their particular rating. This is described at the Android Patterns Site.

See Also:

RatingBar in the 'Form Stuff' tutorial on Android.com

An MVC tutorial that also shows how to construct your own RatingBar-like View component.

No records found.