SeekBar & RatingBar

SeekBar and RatingBar are both sliders in spirit — the user drags to pick a numeric value — but they look and behave differently enough to deserve separate treatment. Both are genuinely simple widgets, yet it's easy to forget the exact listener method names for each, so this lesson doubles as a quick reference too.

SeekBar: Dragging to Pick a Number

RecipeBox uses a SeekBar on the recipe list screen as a "Prep Time" filter — drag it to only show recipes that can be made in under N minutes:

<SeekBar
    android:id="@+id/sbPrepTimeFilter"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="120"
    android:progress="60" />

<TextView
    android:id="@+id/tvPrepTimeLabel"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Under 60 minutes" />

android:max sets the highest value the bar can reach (120 minutes here); android:progress sets the starting position. Reacting to drags in real time requires an OnSeekBarChangeListener:

SeekBar sbPrepTimeFilter = findViewById(R.id.sbPrepTimeFilter);
TextView tvPrepTimeLabel = findViewById(R.id.tvPrepTimeLabel);

sbPrepTimeFilter.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        tvPrepTimeLabel.setText("Under " + progress + " minutes");
        if (fromUser) {
            filterRecipesByMaxPrepTime(progress);
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) { }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) { }
});
Explanation:
  • onProgressChanged() fires continuously while dragging, and also whenever setProgress() is called from code.
  • The fromUser flag distinguishes a real drag from a programmatic update — check it before triggering expensive work like re-filtering a list, so restoring saved state doesn't accidentally re-trigger a filter pass.
  • onStartTrackingTouch/onStopTrackingTouch fire once each, at the beginning and end of a drag gesture — useful if you only want to act once the user lifts their finger.
  • All three methods must be implemented; there's no single-method shortcut here, so this listener is usually written as an anonymous class rather than a lambda.

RatingBar: Read-Only Display

RecipeBox shows a recipe's average rating from other users as stars. Since the user shouldn't be able to change someone else's average, this RatingBar is set to be an indicator only:

<RatingBar
    android:id="@+id/rbAverageRating"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:numStars="5"
    android:stepSize="0.5"
    android:isIndicator="true"
    android:rating="4.5" />
RatingBar rbAverageRating = findViewById(R.id.rbAverageRating);
rbAverageRating.setRating(recipe.averageRating); // e.g. 4.5f, loaded from the database
Explanation: android:isIndicator="true" makes the stars purely visual — taps don't change the value. numStars sets how many stars are drawn; stepSize sets the smallest increment (0.5 allows half stars).

RatingBar: Interactive Input

RecipeBox also lets the current user submit their own rating for a recipe they've cooked. This RatingBar is interactive, so it omits isIndicator and listens for changes:

<RatingBar
    android:id="@+id/rbMyRating"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:numStars="5"
    android:stepSize="1"
    android:rating="0" />
RatingBar rbMyRating = findViewById(R.id.rbMyRating);

rbMyRating.setOnRatingBarChangeListener((ratingBar, rating, fromUser) -> {
    if (fromUser) {
        submitUserRating(recipe.id, rating);
    }
});
Explanation: unlike OnSeekBarChangeListener, OnRatingBarChangeListener has exactly one method (onRatingChanged), so it is a functional interface and works nicely as a lambda. The fromUser parameter serves the same purpose as on SeekBar — it's true only when the user actually dragged the stars.

Quick Reference

WidgetListener interfaceKey method(s)Key XML attrs
SeekBarOnSeekBarChangeListeneronProgressChanged, onStartTrackingTouch, onStopTrackingTouchandroid:max, android:progress
RatingBarOnRatingBarChangeListeneronRatingChangedandroid:numStars, android:stepSize, android:isIndicator
Next up: showing RecipeBox's whole recipe collection as a scrolling list → RecyclerView Basics.