Constructing a RatingBar using images loaded from the web

荒凉一梦 提交于 2019-11-27 02:17:24

问题


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.


回答1:


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.




回答2:


Your ids are wrong, you have to set @android:id/background @android:id/secondaryProgress @android:id/progress

You can also define a drawable in xml containing your customization

<?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/star_empty" />
    <item android:id="@+android:id/secondaryProgress"
          android:drawable="@drawable/star_empty" />
    <item android:id="@+android:id/progress"
          android:drawable="@drawable/star_full" />
</layer-list>

And you can use setMax on the RatingBar object to set the maximum amount of stars that can be displayed




回答3:


It's much easier with such solution:

RatingBar ratingBar = new RatingBar(new ContextThemeWrapper(context, R.style.AppTheme_RatingBar), null, 0);


来源:https://stackoverflow.com/questions/15027475/constructing-a-ratingbar-using-images-loaded-from-the-web

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!