I have a form which I'm dynamically generating from data I receive from a web service. This web service provides images which need to be used in the creation of input elements. I'm having difficuly in setting the progressDrawable
of a RatingBar
. Though XML I'm able to apply a custom image using the following as the progressDrawable
:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+android:id/background" android:drawable="@drawable/custom_star" />
<item android:id="@+android:id/secondaryProgress" android:drawable="@drawable/custom_star" />
<item android:id="@+android:id/progress" android:drawable="@drawable/custom_star" />
</layer-list>
where custom_star
is a simple .png image, and with @android:style/Widget.RatingBar
as the RatingBar style. This works fine:
but I'm wanting to change custom_star
dynamically.
In code, I have tried setting the progress drawable using a bitmap directly:
Drawable d = new BitmapDrawable(getResources(), downloadedImage);
ratingBar.setProgressDrawable(d);
and also by constructing a layer-list
:
LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] {
getResources().getDrawable(R.drawable.custom_star),
getResources().getDrawable(R.drawable.custom_star),
getResources().getDrawable(R.drawable.custom_star)
});
layerDrawable.setId(0, android.R.id.background);
layerDrawable.setId(1, android.R.id.secondaryProgress);
layerDrawable.setId(2, android.R.id.progress);
ratingBar.setProgressDrawable(layerDrawable);
Neither works for me; both result in the custom_star
drawable appearing once, stretched by the dimensions of the RatingBar
:
Any ideas?
Update:
Luksprog's answer below has made an improvement, but I'm still having a couple of issues. Now, the star drawable is not stretched and the value can be set by touch, but it appears as so with 3/5 selected:
and 5/5 selected:
I believe the scaling of the images can be fixed with a few tweaks, but annoyingly the secondaryProgress
drawable doesn't seem to be set - the drawable used for the greyed out not-selected stars. Without that, it's not very usable.
Any ideas?
When using the default progressDrawable
or a progressDrawable
set through a theme all will be ok as in the constructor for the RatingBar
(its superclass ProgressBar
to be more precise) widget a method will be called to "make tiles" from that drawable. When using the setProgressDrawable
method this doesn't happen and if you pass a simple BitmapDrawable
or a LayerDrawable
(with simple BitmapDrawables
) that Drawable
will simply be stretched to cover the widget's background area(what you see know).
In order to make it work you would need to manually do what the RatingBar
does at start, create the tiles along with the ClipDrawables
that it uses. I've written a method for this, following the source code of the ProgressBar
widget:
private Drawable buildRatingBarDrawables(Bitmap[] images) {
final int[] requiredIds = { android.R.id.background,
android.R.id.secondaryProgress, android.R.id.progress };
final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
Drawable[] pieces = new Drawable[3];
for (int i = 0; i < 3; i++) {
ShapeDrawable sd = new ShapeDrawable(new RoundRectShape(
roundedCorners, null, null));
BitmapShader bitmapShader = new BitmapShader(images[i],
Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
sd.getPaint().setShader(bitmapShader);
ClipDrawable cd = new ClipDrawable(sd, Gravity.LEFT,
ClipDrawable.HORIZONTAL);
if (i == 0) {
pieces[i] = sd;
} else {
pieces[i] = cd;
}
}
LayerDrawable ld = new LayerDrawable(pieces);
for (int i = 0; i < 3; i++) {
ld.setId(i, requiredIds[i]);
}
return ld;
}
Then you would use the LayerDrawable
returned by this method with the setProgressDrawable
method. The RatingBar
set its width multiplying the width of one of the state bitmaps with the number of stars, so in order to show the right amount of stars this has to be calculated as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With