构建使用从卷筒纸加载的图像一个的RatingBar图像、加载、卷筒纸、RatingBar

2023-09-05 10:35:43 作者:涟 漪

我有一个形式,我从动态数据,我从一个Web服务接收产生。此Web服务提供了需要在创建输入元素的使用图像。我在设置 progressDrawable一个的RatingBar 有difficuly。虽然XML我可以使用下面的应用自定义图像 progressDrawable

 <层列表的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android>
    <项目机器人:ID =@ +安卓ID /背景机器人:可绘制=@可绘制/ custom_star/>
    <项目机器人:ID =@ +安卓ID / secondaryProgress机器人:可绘制=@可绘制/ custom_star/>
    <项目机器人:ID =@ +安卓ID /进步的机器人:可绘制=@可绘制/ custom_star/>
< /层列表>
 

其中, custom_star 是一个简单的PNG图片,并用 @android:款式/ Widget.RatingBar 作为的RatingBar风格。这工作得很好:

但我想改变 custom_star 动态。

在code,我曾尝试直接使用位图设置进度绘制:

 绘制对象D =新BitmapDrawable(getResources(),downloadedImage);
ratingBar.setProgressDrawable(四);
 
关于输出透明gif

和还通过构建一个图层列表

  LayerDrawable layerDrawable =新LayerDrawable(新绘制对象[] {
    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);
 

无论是对我的作品;无论导致 custom_star 绘制出现一次,由尺寸拉伸的RatingBar

任何想法?

更新:

Luksprog的回答下面做出了改进,但我仍然有几个问题。现在,星绘制没有被拉伸和值可通过触摸来进行设置,但它似乎是如此有3/5选择:

和5/5选择:

我相信,图像的缩放比例可以固定了一些调整,但烦人的 secondaryProgress 绘制似乎并没有被设置 - 用于灰色的绘制不加选择的明星。如果没有这些,这不是非常有用。

解决方案   

任何想法?

在使用默认 progressDrawable progressDrawable 通过一个主题都将是不错的方法,在构造函数设置在的RatingBar (它的超进度更precise)小部件的方法将被称为使瓷砖从绘制。当使用 setProgressDrawable 方法,这不会发生,如果你通过一个简单的 BitmapDrawable LayerDrawable (用简单的 BitmapDrawables )的绘制对象将简单地延伸到覆盖部件的背景区域(你所看到的都知道)。

为了使它工作,你需要手动做什么的RatingBar 并在启动时,创建切片随着 ClipDrawables ,它使用。我写了这样的方法,继进度部件的来源$ C ​​$ C:

 私人绘​​制对象buildRatingBarDrawables(位图[]的图像){
    最终诠释[] requiredIds = {android.R.id.background,
            android.R.id.secondaryProgress,android.R.id.progress};
    最终浮动[] roundedCorners =新的浮动[] {5,5,5,5,5,5,5,5};
    绘制对象[] =件新绘制对象[3]。
    的for(int i = 0;我3;;我++){
        ShapeDrawable SD =新ShapeDrawable(新RoundRectShape(
                roundedCorners,NULL,NULL));
        BitmapShader bitmapShader =新BitmapShader(图像[我],
                Shader.TileMode.REPEAT,Shader.TileMode.CLAMP);
        sd.getPaint()setShader(bitmapShader)。
        ClipDrawable CD =新ClipDrawable(SD,Gravity.LEFT,
                ClipDrawable.HORIZONTAL);
        如果(我== 0){
            件[I] = SD;
        } 其他 {
            件[I] = CD;
        }
    }
    LayerDrawable LD =新LayerDrawable(件);
    的for(int i = 0;我3;;我++){
        ld.setId(ⅰ,requiredIds [I]);
    }
    返回LD;
}
 

然后,你可以使用 LayerDrawable 此方法与 setProgressDrawable 方法返回。该的RatingBar 设置它的宽度来计算的,以及为了表现分这有适量乘以状态的位图与数星星之一的宽度,所以

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.