You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现支持部分填充的Rating bar五星评分系统?

实现支持部分填充的五星评分条

方案一:使用 LayerDrawable + ClipDrawable 组合(基于图片实现)

这种方式适合已有设计好的空星/满星图片的场景,步骤简单:

  1. 准备资源:

    • 空星图片:unfilled_star.png
    • 满星图片:filled_star.png
  2. 定义单个星星的组合Drawable(res/drawable/star_item.xml):

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 底层空星 -->
    <item android:drawable="@drawable/unfilled_star" />
    <!-- 上层可裁剪的满星 -->
    <item>
        <clip
            android:drawable="@drawable/filled_star"
            android:clipOrientation="horizontal"
            android:gravity="left" />
    </item>
</layer-list>
  1. 布局中放置5个ImageView:
<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView android:id="@+id/star1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star_item"/>
    <ImageView android:id="@+id/star2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star_item"/>
    <ImageView android:id="@+id/star3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star_item"/>
    <ImageView android:id="@+id/star4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star_item"/>
    <ImageView android:id="@+id/star5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star_item"/>
</LinearLayout>
  1. 代码中计算填充比例:
float rating = 3.3f;
ImageView[] stars = {findViewById(R.id.star1), findViewById(R.id.star2), findViewById(R.id.star3), findViewById(R.id.star4), findViewById(R.id.star5)};

for (int i = 0; i < stars.length; i++) {
    float currentStarRating = rating - i;
    LayerDrawable layerDrawable = (LayerDrawable) stars[i].getDrawable();
    ClipDrawable clipDrawable = (ClipDrawable) layerDrawable.getDrawable(1);
    
    if (currentStarRating >= 1) {
        clipDrawable.setLevel(10000); // 完全填充(ClipDrawable的level范围0-10000)
    } else if (currentStarRating > 0) {
        clipDrawable.setLevel((int) (currentStarRating * 10000)); // 按比例填充
    } else {
        clipDrawable.setLevel(0); // 不填充
    }
}

方案二:自定义View直接绘制(无图片依赖)

这种方式更灵活,不需要外部图片,直接通过Canvas绘制星星形状,适配性更强:

  1. 自定义RatingBar类:
public class PartialRatingBar extends View {
    private float mRating;
    private final int mStarCount = 5;
    private Paint mUnfilledPaint;
    private Paint mFilledPaint;
    private float mStarSize;
    private float mStarSpacing;

    public PartialRatingBar(Context context) {
        super(context);
        init();
    }

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

    private void init() {
        // 初始化空星画笔
        mUnfilledPaint = new Paint();
        mUnfilledPaint.setColor(Color.parseColor("#D3D3D3"));
        mUnfilledPaint.setStyle(Paint.Style.STROKE);
        mUnfilledPaint.setStrokeWidth(2);
        mUnfilledPaint.setAntiAlias(true);

        // 初始化满星画笔
        mFilledPaint = new Paint();
        mFilledPaint.setColor(Color.parseColor("#FFD700"));
        mFilledPaint.setStyle(Paint.Style.FILL);
        mFilledPaint.setAntiAlias(true);

        // 设置星星大小和间距(可根据需求调整)
        mStarSize = dpToPx(24);
        mStarSpacing = dpToPx(4);
    }

    // 设置评分
    public void setRating(float rating) {
        mRating = Math.max(0, Math.min(rating, mStarCount));
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float totalWidth = mStarCount * mStarSize + (mStarCount - 1) * mStarSpacing;
        float startX = (getWidth() - totalWidth) / 2;
        float startY = getHeight() / 2;

        for (int i = 0; i < mStarCount; i++) {
            float currentX = startX + i * (mStarSize + mStarSpacing);
            // 绘制空星轮廓
            drawStar(canvas, mUnfilledPaint, currentX, startY, mStarSize);
            
            // 计算当前星星的填充比例
            float fillRatio = mRating - i;
            if (fillRatio > 0) {
                fillRatio = Math.min(fillRatio, 1);
                // 裁剪画布,绘制填充部分
                canvas.save();
                canvas.clipRect(currentX, startY - mStarSize/2, currentX + mStarSize * fillRatio, startY + mStarSize/2);
                drawStar(canvas, mFilledPaint, currentX, startY, mStarSize);
                canvas.restore();
            }
        }
    }

    // 绘制五角星路径
    private void drawStar(Canvas canvas, Paint paint, float centerX, float centerY, float size) {
        Path path = new Path();
        float outerRadius = size / 2;
        float innerRadius = outerRadius * 0.4f;
        float angle = (float) (Math.PI / 5);

        for (int j = 0; j < 10; j++) {
            float radius = (j % 2 == 0) ? outerRadius : innerRadius;
            float x = (float) (centerX + radius * Math.cos(j * angle - Math.PI / 2));
            float y = (float) (centerY + radius * Math.sin(j * angle - Math.PI / 2));
            if (j == 0) {
                path.moveTo(x, y);
            } else {
                path.lineTo(x, y);
            }
        }
        path.close();
        canvas.drawPath(path, paint);
    }

    // dp转px工具方法
    private float dpToPx(float dp) {
        return dp * getContext().getResources().getDisplayMetrics().density;
    }
}
  1. 布局中使用自定义View:
<com.yourpackage.PartialRatingBar
    android:id="@+id/partialRatingBar"
    android:layout_width="wrap_content"
    android:layout_height="40dp" />
  1. 代码中设置评分:
PartialRatingBar ratingBar = findViewById(R.id.partialRatingBar);
ratingBar.setRating(3.3f);

内容的提问来源于stack exchange,提问作者other4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 20:05:21