自定义CustomRatingBar控件

通过自定义RatingBar的样式实现⭐️⭐️⭐️指示器的方式功能过于受限,而且显示的样式阴影会受到影响。

系统自带显示:
在这里插入图片描述
自定义样式:
在这里插入图片描述

因此简单自一个符合要求的 CustomRatingBar

  • 支持设置星星数量
  • 支持设置星星Rating(float)
  • 支持设置空显示
  • 支持设置半空显示
  • 支持设置全显示
  • 支持设置星星之间的间距
  • 支持设置星星的宽高

1. 创建自定义 RatingBar 类

首先,创建一个自定义的 RatingBar 类,继承自 View,并重写相关方法。

import android.content.Context
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import com.example.yourapp.R

class CustomRatingBar @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private var starCount = 5 // 星星数量
    private var rating = 0f // 当前评分
    private var starSpacing = 0 // 星星间距
    private var starWidth = 0 // 星星宽度
    private var starHeight = 0 // 星星高度
    private var starEmptyDrawable: Drawable? = null
    private var starHalfDrawable: Drawable? = null
    private var starFullDrawable: Drawable? = null

    init {
        val a = context.theme.obtainStyledAttributes(attrs, R.styleable.CustomRatingBar, 0, 0)
        try {
            starCount = a.getInteger(R.styleable.CustomRatingBar_starCount, starCount)
            rating = a.getFloat(R.styleable.CustomRatingBar_rating, rating)
            starSpacing = a.getDimensionPixelSize(R.styleable.CustomRatingBar_starSpacing, starSpacing)
            starWidth = a.getDimensionPixelSize(R.styleable.CustomRatingBar_starWidth, 0)
            starHeight = a.getDimensionPixelSize(R.styleable.CustomRatingBar_starHeight, 0)
            starEmptyDrawable = a.getDrawable(R.styleable.CustomRatingBar_starEmpty)
            starHalfDrawable = a.getDrawable(R.styleable.CustomRatingBar_starHalf)
            starFullDrawable = a.getDrawable(R.styleable.CustomRatingBar_starFull)
        } finally {
            a.recycle()
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width: Int
        val height: Int

        if (starWidth > 0) {
            width = starWidth * starCount + starSpacing * (starCount - 1)
        } else {
            width = MeasureSpec.getSize(widthMeasureSpec)
            starWidth = (width - starSpacing * (starCount - 1)) / starCount
        }

        height = if (starHeight > 0) {
            starHeight
        } else {
            starWidth
        }

        setMeasuredDimension(width, height)
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        if (starEmptyDrawable == null || starHalfDrawable == null || starFullDrawable == null) {
            return
        }

        for (i in 0 until starCount) {
            val starRating = rating - i
            val drawable = when {
                starRating >= 1 -> starFullDrawable
                starRating >= 0.5 -> starHalfDrawable
                else -> starEmptyDrawable
            }
            val left = i * (starWidth + starSpacing)
            val right = left + starWidth
            drawable?.setBounds(left, 0, right, height)
            drawable?.draw(canvas)
        }
    }

    fun setRating(rating: Float) {
        this.rating = rating
        invalidate()
    }

    fun getRating(): Float = rating

    fun setStarCount(starCount: Int) {
        this.starCount = starCount
        requestLayout()
        invalidate()
    }

    fun getStarCount(): Int = starCount

    fun setStarSpacing(spacing: Int) {
        this.starSpacing = spacing
        requestLayout()
        invalidate()
    }

    fun getStarSpacing(): Int = starSpacing

    fun setStarWidth(width: Int) {
        this.starWidth = width
        requestLayout()
        invalidate()
    }

    fun getStarWidth(): Int = starWidth

    fun setStarHeight(height: Int) {
        this.starHeight = height
        requestLayout()
        invalidate()
    }

    fun getStarHeight(): Int = starHeight

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> {
                val newRating = (event.x / width * starCount).toInt() + 1
                setRating(newRating.toFloat())
                return true
            }
        }
        return super.onTouchEvent(event)
    }
}

2. 自定义属性

在 res/values/attrs.xml 文件中添加星星宽高的自定义属性:

<declare-styleable name="CustomRatingBar">
    <attr name="starCount" format="integer" />
    <attr name="rating" format="float" />
    <attr name="starSpacing" format="dimension" />
    <attr name="starWidth" format="dimension" />
    <attr name="starHeight" format="dimension" />
    <attr name="starEmpty" format="reference" />
    <attr name="starHalf" format="reference" />
    <attr name="starFull" format="reference" />
</declare-styleable>

3. 使用自定义 RatingBar

在你的布局文件中使用自定义的 CustomRatingBar 并设置星星宽高和间距:

<com.example.yourapp.CustomRatingBar
    android:id="@+id/customRatingBar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:starCount="5"
    app:rating="3.5"
    app:starSpacing="8dp"
    app:starWidth="40dp"
    app:starHeight="40dp"
    app:starEmpty="@drawable/star_empty"
    app:starHalf="@drawable/star_half"
    app:starFull="@drawable/star_full" />

4. 在代码中设置星级、间距、宽度和高度

在你的 Activity 或 Fragment 中设置星级、星星间距、宽度和高度:

val ratingBar: CustomRatingBar = findViewById(R.id.customRatingBar)
ratingBar.setRating(4.0f)
ratingBar.setStarSpacing(16) // 设置星星间距为16像素
ratingBar.setStarWidth(60)   // 设置星星宽度为60像素
ratingBar.setStarHeight(60)  // 设置星星高度为60像素

这样就完成了一个支持设置星星数量、三种状态、星星之间间距以及星星宽高的自定义 RatingBar 指示器。

在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值