Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom RatingBar tinting API < 21 with support library 22.1.1

I'm using the support library 22.1.1. My goal is to tint a custom RatingBar to avoid having to include multiple images in my APK.

The tinting is correctly applied on API 22, but not on API 19. I'd like it to work on API >= 16. Note that I'm trying to tint the "progress" only, not the full bar.

Here is the RatingBar style:

<style name="customRatingBar" parent="Widget.AppCompat.RatingBar">
    <item name="android:progressDrawable">@drawable/custom_ratingbar</item>
    <item name="android:minHeight">24dp</item>
    <item name="android:maxHeight">24dp</item>
    <item name="android:progressTint">@color/md_red_700</item>
    <item name="android:secondaryProgressTint">@color/md_red_700</item>
</style>

And the custom_ratingbar.xml file:

<?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/ic_heart_outline_grey600_24dp" />
    <item android:id="@android:id/progress"
        android:drawable="@drawable/ic_heart_grey600_24dp" />
</layer-list>

It's applied that way in my layout, which is in a fragment extending android.support.v4.Fragment itself inside an activity extending android.support.v7.app.AppCompatActivity:

<RatingBar
    android:layout_width="wrap_content"
    android:layout_height="22dp"
    android:id="@+id/checkin_rating"
    style="@style/customRatingBar"
    android:isIndicator="true"
    android:numStars="5"
    android:stepSize="1"
    android:layout_marginBottom="8dp"/>

I get a warning from the lint tools saying that android:progressTint is not supported on API < 21. Is there any way to achieve this without using several drawables?

like image 438
Marc Demierre Avatar asked May 23 '15 14:05

Marc Demierre


2 Answers

With support library > 22 I managed to do this using getProgressDrawable

LayerDrawable stars = (LayerDrawable) bar.getProgressDrawable();
stars.getDrawable(0).setColorFilter(NONE_COLOR, PorterDuff.Mode.SRC_ATOP);
stars.getDrawable(1).setColorFilter(FULL_COLOR, PorterDuff.Mode.SRC_ATOP);
stars.getDrawable(2).setColorFilter(PARTIAL_COLOR, PorterDuff.Mode.SRC_ATOP);

This didn't work before support library 22 so I think this will solve your problem.

like image 143
Gary Damême Avatar answered Oct 23 '22 11:10

Gary Damême


I didn't want to necessarily edit Gary's answer which has been accepted (if I even can) but I found the order of FULL/PARTIAL/NONE wasn't correct for me. This is how I implemented it and it works for API 18+.

To set the starbar (my subclass of AppCompatRatingBar) yellow with gray for unfilled stars:

    int yellow = ContextCompat.getColor(getContext(), R.color.starbar_star_yellow);
    int gray = ContextCompat.getColor(getContext(), R.color.starbar_star_gray);

    Drawable starbarDrawable = this.getProgressDrawable();
    DrawableCompat.setTint(starbarDrawable, yellow); // this works for API 21+

    // this ensures it works for API 18-20
    if(starbarDrawable instanceof LayerDrawable) {
        LayerDrawable stars = (LayerDrawable) starbarDrawable;
        stars.getDrawable(0).setColorFilter(gray, PorterDuff.Mode.SRC_ATOP); // UNFILLED
        stars.getDrawable(1).setColorFilter(yellow, PorterDuff.Mode.SRC_ATOP); // PARTIAL OR FULL?
        stars.getDrawable(2).setColorFilter(yellow, PorterDuff.Mode.SRC_ATOP); // PARTIAL OR FULL?
    }
like image 42
the_dude_abides Avatar answered Oct 23 '22 12:10

the_dude_abides