如何在安卓系统中创建自定义评分栏

87

大家好,我需要在我的应用程序中进行评级...所以我需要创建自定义评级栏...有人可以帮我吗?


6
提供一些代码片段(也许是您目标的模拟),以便查看您目前的进展。从您的帖子中看,它不像一个需要解决的问题,更像是一个工作提议,请详细说明。 - rekaszeru
14个回答

157

styles.xml

这个必须放在你的values文件夹中

 <?xml version="1.0" encoding="utf-8"?>
  <resources>
    <style name="foodRatingBar" parent="@android:style/Widget.RatingBar">
       <item name="android:progressDrawable">@drawable/food_rating_bar_full</item>
       <item name="android:minHeight">23dip</item>
       <item name="android:maxHeight">25dip</item>
   </style>
  </resources>

food_rating_bar_full.xml

该文件必须位于Drawable文件夹中。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/background"
    android:drawable="@drawable/food_ratingbar_full_empty" />
    <item android:id="@+id/secondaryProgress"
    android:drawable="@drawable/food_ratingbar_full_empty" />
    <item android:id="@+id/progress"
    android:drawable="@drawable/food_ratingbar_full_filled" />
</layer-list>

food_ratingbar_full_empty.xml

这个文件必须放在Drawable文件夹内。

<?xml version="1.0" encoding="utf-8"?>

<!-- This is the rating bar drawable that is used to
 show a filled cookie. -->
<selector
xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_pressed="true"
      android:state_window_focused="true"
      android:drawable="@drawable/cookiee" />

<item android:state_focused="true"
      android:state_window_focused="true"
      android:drawable="@drawable/cookiee" />

<item android:state_selected="true"
      android:state_window_focused="true"
      android:drawable="@drawable/cookiee" />

<item android:drawable="@drawable/cookiee" />

</selector>

food_ratingbar_full_filled.xml

这个文件必须位于Drawable文件夹中。

<?xml version="1.0" encoding="utf-8"?>

 <!-- This is the rating bar drawable that is used to
 show a unfilled cookie. -->
<selector
xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_pressed="true"
      android:state_window_focused="true"
      android:drawable="@drawable/cookie" />

<item android:state_focused="true"
      android:state_window_focused="true"
      android:drawable="@drawable/cookie" />

<item android:state_selected="true"
      android:state_window_focused="true"
      android:drawable="@drawable/cookie" />

<item android:drawable="@drawable/cookie" />

</selector>

main.xml文件应该长这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <RatingBar android:id="@+id/ratingBar1"
        style="@style/foodRatingBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
            
    </RatingBar>
</LinearLayout>

MainActivity.class 应该如下所示:

import android.app.Activity;
import android.os.Bundle;
import android.widget.RatingBar;
import android.widget.RatingBar.OnRatingBarChangeListener;
import android.widget.Toast;

public class MainActivity extends Activity {
/** Called when the activity is first created. */

RatingBar rb;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    rb=(RatingBar)findViewById(R.id.ratingBar1);
    
    rb.setOnRatingBarChangeListener(new OnRatingBarChangeListener(){

        @Override
        public void onRatingChanged(RatingBar ratingBar, float rating,
                boolean fromUser) {
            // TODO Auto-generated method stub
                Toast.makeText(getApplicationContext(),Float.toString(rating),Toast.LENGTH_LONG).show();
            
        }
        
    }); 
}
}

我使用了两张图片:

cookie.jpg

cookiee.jpg

这两张图片大小相同,一张用于识别已选择的评分条,另一张用于识别未选择的评分条。


22
在 food_rating_bar_full.xml 文件中更改项目 ID 后,这对我起了作用。我将 <item android:id="@+android:id/background" 替换为 <item android:id="@android:id/background"(没有 + 符号)。请注意,不要改变原来的意思。 - R. Campos
1
帖子中的第一个链接已经失效。 - Simon Schnell
1
链接无法访问 http://kozyr.zydako.net/2010/05/23/pretty-ratingbar/ - Jay Rathod
14
与 @erdomester 建议的相同,但需要更多代码。注意:不要忘记它不适用于矢量图像,只适用于 .png 格式! - Kirill Karmazin
4
对我没有用,但当我将以下内容替换时就可以了:
  • android:id="@+id/background" 替换为 @android:id/background
  • android:id="@+id/secondaryProgress" 替换为 android:id="@android:id/secondaryProgress"
  • android:id="@+id/progress" 替换为 android:id="@android:id/progress"
- Haris
显示剩余7条评论

62

我需要添加我的解决方案,它比上面那个要简单得多。我们甚至不需要使用样式。

在drawable文件夹中创建一个选择器文件:

custom_ratingbar_selector.xml

<?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_off" />

 <item android:id="@android:id/secondaryProgress"
    android:drawable="@drawable/star_off" />

 <item android:id="@android:id/progress"
    android:drawable="@drawable/star_on" />

</layer-list>
在布局中将选择器文件设置为progressDrawable:
 <RatingBar
        android:id="@+id/ratingBar2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        android:progressDrawable="@drawable/custom_ratingbar_selector"
        android:numStars="8"
        android:stepSize="0.2"
        android:rating="3.0" />

这就是我们所需要的全部。


1
+1,但很抱歉,这应该是可以工作的,但实际上它并没有。首先,你说你添加了选择器,但实际上你添加了一个图层列表。其次,我尝试了你的代码,但我得到的只是一个空白组件(根本没有图像)。也许你可以回答我的问题:https://dev59.com/sG3Xa4cB1Zd3GeqPaAa_ 谢谢:D - Blaze Tama
3
这种简单的方法会导致在布局中定位评分条时出现问题。使用定义样式的更传统方法更好。 - javaxian
5
评分条中所有星星下面都显示了一条线。 - Sunil
6
非常好用,谢谢。注意:请不要忘记它不能处理矢量图像,仅适用于 .png 格式的图片! - Kirill Karmazin
谢谢!关于SVG,请查看我的回答:https://dev59.com/MG025IYBdhLWcg3wyJGV#53589663。 - CoolMind

50

首先将图片添加到drawable文件夹:

enter image description here enter image description here

第一张图片为 "ratingbar_staroff.png",第二张图片为 "ratingbar_staron.png"

然后,在 res/drawable 中创建一个名为 "ratingbar.xml" 的文件。

<?xml version="1.0" encoding="utf-8"?>
<!--suppress AndroidDomInspection -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+android:id/background"
        android:drawable="@drawable/ratingbar_empty" />
    <item android:id="@+android:id/secondaryProgress"
        android:drawable="@drawable/ratingbar_empty" />
    <item android:id="@+android:id/progress"
        android:drawable="@drawable/ratingbar_filled" />
</layer-list>

下一个XML与res/drawable中的相同

"ratingbar_empty.xml"

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true"
        android:state_window_focused="true"
        android:drawable="@drawable/ratingbar_staroff" />

    <item android:state_focused="true"
        android:state_window_focused="true"
        android:drawable="@drawable/ratingbar_staroff" />

    <item android:state_selected="true"
        android:state_window_focused="true"
        android:drawable="@drawable/ratingbar_staroff" />

    <item android:drawable="@drawable/ratingbar_staroff" />

</selector>

"评分条已填满"

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true"
        android:state_window_focused="true"
        android:drawable="@drawable/ratingbar_staron" />

    <item android:state_focused="true"
        android:state_window_focused="true"
        android:drawable="@drawable/ratingbar_staron" />

    <item android:state_selected="true"
        android:state_window_focused="true"
        android:drawable="@drawable/ratingbar_staron" />

    <item android:drawable="@drawable/ratingbar_staron" />

</selector>

接下来要做的是,在res/values/styles中添加这些代码行:

<style name="CustomRatingBar" parent="@android:style/Widget.RatingBar">
    <item name="android:progressDrawable">@drawable/ratingbar</item>
    <item name="android:minHeight">18dp</item>
    <item name="android:maxHeight">18dp</item>
</style>

现在,您已经可以向评分条资源添加样式了

        <RatingBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style= "@style/CustomRatingBar"
            android:id="@+id/ratingBar"
            android:numStars="5"
            android:stepSize="0.01"
            android:isIndicator="true"/>

最后,在你的活动中仅声明即可:

RatingBar ratingbar = (RatingBar) findViewById(R.id.ratingbar);
ratingbar.setRating(3.67f);

输入图像描述


5
这段话的意思是:它类似于已勾选的答案,但有图片(显示分数星级)和<!- -suppress AndroidDomInspection - ->在层列表中。您可以删除 "@+android:id/background" 中的加号以避免出现Android错误。还应将minHeight和maxHeight更改为50dp。 - CoolMind
谢谢你的解决方案。请问如何调整星星的大小?我的星星很小。谢谢。 - jay
@jay 在 res/values/styles 中定义了 android:minHeightandroid:maxHeight,将其更改以使星星大小变大。 - Inzimam Tariq IT
感谢您详细的回答! - Pratik Tank

13

对于SVG RatingBar,我使用了RatingBar custom Vector Drawables superimposing的解决方案,并参考了erdomester的回答。该解决方案遍历布局中SvgRatingBar视图中的所有可绘制对象,因此在RecyclerView中会有一定的开销。

SvgRatingBar.java:

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.VectorDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;

import androidx.appcompat.graphics.drawable.DrawableWrapper;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;

import com.example.R; // Your R.java file for R.attr.ratingBarStyle.

public class SvgRatingBar extends androidx.appcompat.widget.AppCompatRatingBar {

    private Bitmap sampleTile;

    public SvgRatingBar(Context context) {
        this(context, null);
    }

    public SvgRatingBar(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.ratingBarStyle);
    }

    public SvgRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        LayerDrawable drawable = (LayerDrawable) createTile(getProgressDrawable(), false);
        setProgressDrawable(drawable);
    }

    /**
     * Converts a drawable to a tiled version of itself. It will recursively
     * traverse layer and state list drawables.
     */
    @SuppressLint("RestrictedApi")
    private Drawable createTile(Drawable drawable, boolean clip) {
        if (drawable instanceof DrawableWrapper) {
            Drawable inner = ((DrawableWrapper) drawable).getWrappedDrawable();
            if (inner != null) {
                inner = createTile(inner, clip);
                ((DrawableWrapper) drawable).setWrappedDrawable(inner);
            }
        } else if (drawable instanceof LayerDrawable) {
            LayerDrawable background = (LayerDrawable) drawable;
            final int n = background.getNumberOfLayers();
            Drawable[] outDrawables = new Drawable[n];

            for (int i = 0; i < n; i++) {
                int id = background.getId(i);
                outDrawables[i] = createTile(background.getDrawable(i),
                        (id == android.R.id.progress || id == android.R.id.secondaryProgress));
            }
            LayerDrawable newBg = new LayerDrawable(outDrawables);

            for (int i = 0; i < n; i++) {
                newBg.setId(i, background.getId(i));
            }

            return newBg;

        } else if (drawable instanceof BitmapDrawable) {
            final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            final Bitmap tileBitmap = bitmapDrawable.getBitmap();
            if (sampleTile == null) {
                sampleTile = tileBitmap;
            }

            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
            shapeDrawable.getPaint().setShader(bitmapShader);
            shapeDrawable.getPaint().setColorFilter(bitmapDrawable.getPaint().getColorFilter());
            return (clip) ? new ClipDrawable(shapeDrawable, Gravity.START,
                    ClipDrawable.HORIZONTAL) : shapeDrawable;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable) {
            return createTile(getBitmapDrawableFromVectorDrawable(drawable), clip);
        } else if (drawable instanceof VectorDrawableCompat) {
            // API 19 support.
            return createTile(getBitmapDrawableFromVectorDrawable(drawable), clip);
        }
        return drawable;
    }

    private BitmapDrawable getBitmapDrawableFromVectorDrawable(Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return new BitmapDrawable(getResources(), bitmap);
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (sampleTile != null) {
            final int width = sampleTile.getWidth() * getNumStars();
            setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
                    getMeasuredHeight());
        }
    }

    private Shape getDrawableShape() {
        final float[] roundedCorners = new float[]{5, 5, 5, 5, 5, 5, 5, 5};
        return new RoundRectShape(roundedCorners, null, null);
    }
}

在您的布局中:

<com.example.common.control.SvgRatingBar
    android:id="@+id/rate"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:minHeight="13dp"
    android:numStars="5"
    android:progressDrawable="@drawable/rating_bar"
    android:rating="3.5"
    android:stepSize="0.01"
    />

您还需要创建rating_bar.xml,其中包含两个SVG可绘制对象:

<?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_unfilled_star"
        />

    <item
        android:id="@android:id/secondaryProgress"
        android:drawable="@drawable/ic_unfilled_star"
        />

    <item
        android:id="@android:id/progress"
        android:drawable="@drawable/ic_filled_star"
        />

</layer-list>

这里输入图像描述

如果在设计/分割视图中只看到一个星号,请刷新布局:

这里输入图像描述

用Kotlin实现。

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapShader
import android.graphics.Canvas
import android.graphics.Shader
import android.graphics.drawable.*
import android.graphics.drawable.shapes.RoundRectShape
import android.os.Build
import android.util.AttributeSet
import android.view.Gravity
import androidx.appcompat.graphics.drawable.DrawableWrapper
import androidx.appcompat.widget.AppCompatRatingBar
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import com.example.R; // Your R.java file for R.attr.ratingBarStyle.

class SvgRatingBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
                                             defStyleAttr: Int = R.attr.ratingBarStyle) :
    AppCompatRatingBar(context, attrs, defStyleAttr) {

    private var sampleTile: Bitmap? = null
    private val roundedCorners = floatArrayOf(5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f)
    private val roundRectShape = RoundRectShape(roundedCorners, null, null)

    init {
        progressDrawable = createTile(progressDrawable, false) as LayerDrawable
    }

    /**
     * Converts a drawable to a tiled version of itself. It will recursively
     * traverse layer and state list drawables.
     */
    private fun createTile(drawable: Drawable, clip: Boolean): Drawable =
        when {
            drawable is DrawableWrapper -> {
                @SuppressLint("RestrictedApi")
                var inner = drawable.wrappedDrawable
                if (inner != null) {
                    inner = createTile(inner, clip)
                    @SuppressLint("RestrictedApi")
                    drawable.wrappedDrawable = inner
                }
                drawable
            }
            drawable is LayerDrawable -> {
                val n = drawable.numberOfLayers
                val outDrawables = arrayOfNulls<Drawable>(n)
                for (i in 0 until n) {
                    val id = drawable.getId(i)
                    outDrawables[i] = createTile(drawable.getDrawable(i),
                        id == android.R.id.progress || id == android.R.id.secondaryProgress)
                }
                val newBg = LayerDrawable(outDrawables)
                for (i in 0 until n) {
                    newBg.setId(i, drawable.getId(i))
                }
                newBg
            }
            drawable is BitmapDrawable -> {
                val tileBitmap = drawable.bitmap
                if (sampleTile == null) {
                    sampleTile = tileBitmap
                }
                val bitmapShader = BitmapShader(tileBitmap, Shader.TileMode.REPEAT,
                    Shader.TileMode.CLAMP)
                val shapeDrawable = ShapeDrawable(roundRectShape).apply {
                    paint.shader = bitmapShader
                    paint.colorFilter = drawable.paint.colorFilter
                }
                if (clip) ClipDrawable(shapeDrawable, Gravity.START, ClipDrawable.HORIZONTAL)
                else shapeDrawable
            }
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable is VectorDrawable -> {
                createTile(getBitmapDrawableFromVectorDrawable(drawable), clip)
            }
            drawable is VectorDrawableCompat -> {
                // Pre-Lollipop support.
                createTile(getBitmapDrawableFromVectorDrawable(drawable), clip)
            }
            else -> drawable
        }

    private fun getBitmapDrawableFromVectorDrawable(drawable: Drawable): BitmapDrawable {
        val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight,
            Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)
        return BitmapDrawable(resources, bitmap)
    }

    @Synchronized override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        if (sampleTile != null) {
            val width = sampleTile!!.width * numStars
            setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
                measuredHeight)
        }
    }
}

1
非常感谢。它对我有用。 但需要稍微调整一下 Kotlin 构造函数。 - Nguyen
@Nguyen,谢谢!如果你愿意,你可以修改这段代码,我很乐意看到新的东西。 :) - CoolMind
未找到DrawableWrapper导入 - Konstantin Konopko
@KonstantinKonopko,同意。也许可以使用import androidx.appcompat.graphics.drawable.DrawableWrapperCompat - CoolMind
@AlexS,谢谢你!祝你好运! - undefined
显示剩余2条评论

7

使用层列表和选择器来制作自定义评分条非常复杂,最好是覆盖RatingBar类并创建自定义的RatingBar。createBackgroundDrawableShape()是您应该放置空状态png的函数,而createProgressDrawableShape()是您应该放置填充状态png的函数。

注意:此代码目前无法使用svg。

public class CustomRatingBar extends RatingBar {

    @Nullable
    private Bitmap mSampleTile;

    public ShapeDrawableRatingBar(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        setProgressDrawable(createProgressDrawable());
    }

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (mSampleTile != null) {
            final int width = mSampleTile.getWidth() * getNumStars();
            setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0), getMeasuredHeight());
        }
    }

    protected LayerDrawable createProgressDrawable() {
        final Drawable backgroundDrawable = createBackgroundDrawableShape();
        LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{
            backgroundDrawable,
            backgroundDrawable,
            createProgressDrawableShape()
        });

        layerDrawable.setId(0, android.R.id.background);
        layerDrawable.setId(1, android.R.id.secondaryProgress);
        layerDrawable.setId(2, android.R.id.progress);
        return layerDrawable;
    }

    protected Drawable createBackgroundDrawableShape() {
        final Bitmap tileBitmap = drawableToBitmap(getResources().getDrawable(R.drawable.ic_star_empty));
        if (mSampleTile == null) {
            mSampleTile = tileBitmap;
        }
        final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
        final BitmapShader bitmapShader = new BitmapShader(tileBitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
        shapeDrawable.getPaint().setShader(bitmapShader);
        return shapeDrawable;
    }

    protected Drawable createProgressDrawableShape() {
        final Bitmap tileBitmap = drawableToBitmap(getResources().getDrawable(R.drawable.ic_star_full));
        final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
        final BitmapShader bitmapShader = new BitmapShader(tileBitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
        shapeDrawable.getPaint().setShader(bitmapShader);
        return new ClipDrawable(shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL);
    }

    Shape getDrawableShape() {
        final float[] roundedCorners = new float[]{5, 5, 5, 5, 5, 5, 5, 5};
        return new RoundRectShape(roundedCorners, null, null);
    }

    public static Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        int width = drawable.getIntrinsicWidth();
        width = width > 0 ? width : 1;
        int height = drawable.getIntrinsicHeight();
        height = height > 0 ? height : 1;

        final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        final Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }
}

如何增加项目之间的间距? - Ali Rezaiyan
1
@AliRezaiyan:由于我们正在使用自己的可绘制对象,即ic_star_full和ic_star_empty,因此您可以在PNG的左侧和右侧添加空白(填充)。 您可以使用诸如GIMP或Android Asset Studio之类的工具通过编辑PNG来实现这一点。希望这可以帮助到您。 - Gaurav Saluja
我正在寻找一种编程方式 - Ali Rezaiyan

6
我已经调查了原始来源,这是我的结果。 styles.xml(res/values)
<!-- RatingBar -->
<style name="RatingBar" parent="@android:style/Widget.RatingBar">
    <item name="android:progressDrawable">@drawable/ratingbar_full</item>
    <item name="android:indeterminateDrawable">@drawable/ratingbar_full</item>
    <item name="android:minHeight">13.4dp</item>
    <item name="android:maxHeight">13.4dp</item>
</style>

ratingbar_full.xml (res/drawable)

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

btn_rating_star_off_normal.png(res/drawable-xxhdpi)

输入图像描述

btn_rating_star_on_normal.png(res/drawable-xxhdpi)

输入图像描述

activity_ratingbar.xml(res/layout)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.AppCompatRatingBar
        android:id="@+id/ratingbar"
        style="@style/RatingBar"
        android:layout_width="wrap_content"
        android:layout_height="13.4dp"
        android:isIndicator="false"
        android:numStars="5"
        android:rating="2.6"
        android:secondaryProgressTint="#00000000"
        android:stepSize="0.1" />
</FrameLayout>

这是结果。

输入图像描述

  • 请注意,我在layout_height属性中添加了评分条的实际高度(13.4dp),因为如果它是wrap_content,它会在星星下面绘制线条。(在我的情况下,仅在Android Studio的预览中)

为什么上传的图片是gif格式而不是png格式。 - taranjeetsapra
@taranjeetsapra 我不确定为什么它是gif格式,因为我很久以前发布了它,现在也不知道了。 - wonsuc

5
你可以尝试这个具有更好动画效果的评分栏。 SmileyRating

enter image description here


图标点击监听器不起作用,即使设置了setIndicator(false)。 - Ahmad Shahwaiz

3

2
以下代码有效:
@Override
protected synchronized void onDraw(Canvas canvas)
{
    int stars = getNumStars();
    float rating = getRating();
    try
    {
        bitmapWidth = getWidth() / stars;
    }
    catch (Exception e)
    {
        bitmapWidth = getWidth();
    }
    float x = 0;

    for (int i = 0; i < stars; i++)
    {
        Bitmap bitmap;
        Resources res = getResources();
        Paint paint = new Paint();

        if ((int) rating > i)
        {
            bitmap = BitmapFactory.decodeResource(res, starColor);
        }
        else
        {
            bitmap = BitmapFactory.decodeResource(res, starDefault);
        }
        Bitmap scaled = Bitmap.createScaledBitmap(bitmap, getHeight(), getHeight(), true);
        canvas.drawBitmap(scaled, x, 0, paint);
        canvas.save();
        x += bitmapWidth;
    }

    super.onDraw(canvas);
}

1
你可以通过定义可定制的drawable xml来创建自定义材料评分栏,使用所选的材料图标,然后将自定义drawable应用于评分栏,使用progressDrawable属性。
有关自定义评分栏的信息,请参见http://www.zoftino.com/android-ratingbar-and-custom-ratingbar-example 下面的drawable xml使用点赞图标作为评分栏。
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <bitmap
            android:src="@drawable/thumb_up"
            android:tint="?attr/colorControlNormal" />
    </item>
    <item android:id="@android:id/secondaryProgress">
        <bitmap
            android:src="@drawable/thumb_up"
            android:tint="?attr/colorControlActivated" />
    </item>
    <item android:id="@android:id/progress">
        <bitmap
            android:src="@drawable/thumb_up"
            android:tint="?attr/colorControlActivated" />
    </item>
</layer-list>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接