3

I am using

Android RatingBar change star colors

This line of code

    LayerDrawable stars = (LayerDrawable) rating_bar.getProgressDrawable();

works fine on my Nexus 4 emulator API v21. When trying the same code on my Galaxy S4 API v19, I get the following error message:

 Caused by: java.lang.ClassCastException: android.support.v7.internal.widget.TintDrawableWrapper cannot be cast to android.graphics.drawable.LayerDrawable

What is happening?

I am building with the latest build tools 22, my target API is 22 is as well.

Community
  • 1
  • 1
Stephane Maarek
  • 5,202
  • 9
  • 46
  • 87
  • The method might not be supported for API 19 then. Are you just trying to get a drawable from an object and use it somewhere else? – Xjasz Mar 16 '15 at 14:10
  • I'm trying to recolor my rating bar using the code as outlined in the question quoted in my post. What's weird is that a month ago, this was working fine. I think this is due to updating the build tools, target sdk, support libraries or something – Stephane Maarek Mar 16 '15 at 14:14
  • 1
    Indeed, something seems to have changed in the latest API/SDK update (22). All my styled rating bars that used to look fine on all Android versions now only look good on Lollipop and above. On anything less than API 21, they are broken horribly, with just one stretched star being rendered, regardless of the rating value. – Dimitris Kazakos Mar 17 '15 at 00:10
  • 1
    Just did some digging and it seems that API 22 automatically uses the new TintRatingBar class, which does some crazy stuff to the drawables when running on API < 21. Since I had no time to research further, my only solution was to subclass the normal RatingBar and use it instead, which seems to solve the problem by preserving the normal RatingBar behavior. – Dimitris Kazakos Mar 17 '15 at 00:41
  • @DimitrisKazakos, you're describing exactly what I had!! Can you please post on the question how you did subclass RatingBar? – Stephane Maarek Mar 17 '15 at 08:31
  • @Stephane I'm having the same problem, it sucks. You were able to work on all versions? – Daniela Morais Apr 19 '15 at 02:18

5 Answers5

2

What happens is clearly explained in the error message :

TintDrawableWrapper cannot be cast to android.graphics.drawable.LayerDrawable

The support lib creates a wrapper in order to handle retro compatibility, you just need to take it into account. Have a look at the lib implementation, it probably wraps around a LayerDrawable.

You will need to do something along the lines of :

LayerDrawable stars = getProgressDrawable(rating_bar);
}

private LayerDrawable getProgressDrawable(RatingBar ratingBar) {
  if (Build.VERSION >= LOLLIPOP) {
    return (LayerDrawable) ratingBar.getProgressDrawable();
  } else {
    // fetch the LayerDrawable based on Google's support implementation,  
    // probably a simple findViewById()
  }
}
Teovald
  • 4,369
  • 4
  • 26
  • 45
  • I have added some pointers, you will have to look at google's implementation in order to see how it is backported. – Teovald Mar 16 '15 at 15:56
  • @Teovald Can you please show the support implementation? I can't seem to find it. – Gofilord Jun 19 '15 at 14:33
  • @Gofilord : http://androidxref.com/5.1.0_r1/xref/frameworks/support/v7/appcompat/src/android/support/v7/internal/widget/TintDrawableWrapper.java is this what you are looking for ? – Teovald Jun 19 '15 at 16:52
  • 1
    I meant what you actually put in the `else` to get the layer drawable on lower API levels. – Gofilord Jun 19 '15 at 17:28
0

LayerDrawable is used in API v21.

jihoon kim
  • 1,270
  • 1
  • 16
  • 22
0

Creating a subclass of RatingDialog and using that instead ofandroid.widget.RatingBar worked for me. Here is the code I used.

Subclass:

public class RatingBar extends android.widget.RatingBar {
public RatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

public RatingBar(Context context, AttributeSet attrs) {
    super(context, attrs);
}
}

Then in my layouts:

 <your.package.RatingBar
    android:id="@+id/rating_bar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="10dp"
    android:layout_marginBottom="10dp"
    />

Then in the classes where you are casting the class, just use your.package.RatingBar instead of android.widget.RatingBar

Chriskot
  • 647
  • 4
  • 7
0

Came accross the same issue today when creating a RatingBar programmatically. The following workaround is working for me also on Android 4.x devices using the AppCompatRatingBar:

AppCompatRatingBar rb = new AppCompatRatingBar(activity);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER;
rb.setLayoutParams(layoutParams);
rb.setStepSize(1.0f);
rb.setMax(5);

LayerDrawable layerDrawable = null;
if (rb.getProgressDrawable() instanceof LayerDrawable) {
    layerDrawable = (LayerDrawable) rb.getProgressDrawable();
} else if (rb.getProgressDrawable() instanceof DrawableWrapper) {
    DrawableWrapper wrapper = (DrawableWrapper) rb.getProgressDrawable();
    if (wrapper.getWrappedDrawable() instanceof LayerDrawable) {
        layerDrawable = (LayerDrawable) wrapper.getWrappedDrawable();
    }
}

if (layerDrawable != null) {
    layerDrawable.getDrawable(2).setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
    layerDrawable.getDrawable(0).setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP);
    layerDrawable.getDrawable(1).setColorFilter(ContextCompat.getColor(activity, R.color.primary), PorterDuff.Mode.SRC_ATOP);
}
Tobias
  • 7,282
  • 6
  • 63
  • 85
0

Please try this trick, It will work fine by adding getCurrent() method to return a drawable.

RatingBar ratingBar = (RatingBar) findViewById(R.id.ratingBar);

LayerDrawable stars = (LayerDrawable) ratingBar.getProgressDrawable().getCurrent();

stars.getDrawable(2).setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.SRC_ATOP); stars.getDrawable(0).setColorFilter(getResources().getColor(R.color.white), PorterDuff.Mode.SRC_ATOP); stars.getDrawable(1).setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.SRC_ATOP);

Kishore
  • 261
  • 3
  • 3