如何实现支持部分填充的Rating bar五星评分系统?
实现支持部分填充的五星评分条
方案一:使用 LayerDrawable + ClipDrawable 组合(基于图片实现)
这种方式适合已有设计好的空星/满星图片的场景,步骤简单:
准备资源:
- 空星图片:
unfilled_star.png - 满星图片:
filled_star.png
- 空星图片:
定义单个星星的组合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>
- 布局中放置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>
- 代码中计算填充比例:
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绘制星星形状,适配性更强:
- 自定义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; } }
- 布局中使用自定义View:
<com.yourpackage.PartialRatingBar android:id="@+id/partialRatingBar" android:layout_width="wrap_content" android:layout_height="40dp" />
- 代码中设置评分:
PartialRatingBar ratingBar = findViewById(R.id.partialRatingBar); ratingBar.setRating(3.3f);
内容的提问来源于stack exchange,提问作者other4
相关产品推荐
相关产品推荐

