Kotlin中实现星级评价选择功能(仅支持整数)

效果图

1.在res下values添加attr.xml

XML 复制代码
        <declare-styleable name="CustomRatingBar">
            <attr name="starCount" format="integer" /><!-- 总共有几颗星-->
            <attr name="rating" format="float" /><!-- 默认选择几颗星-->
            <attr name="starSpacing" format="dimension" /><!--padding值-->
            <attr name="starEmpty" format="reference" /><!--选中后的图片-->
            <attr name="starFull" format="reference" /><!--未选中时的图片-->
        </declare-styleable>

2.自定义View(支持手势左右滑动选中)

Kotlin 复制代码
import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.MotionEvent
import android.widget.ImageView
import android.widget.LinearLayout

class CustomRatingBar @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : LinearLayout(context, attrs) {

    private var starCount = 5
    var currentRating = 0f
    var mRating = 0f
    private var starSpacing = 8
    private val starViews = mutableListOf<ImageView>()

    init {
        orientation = HORIZONTAL
        gravity = Gravity.CENTER_VERTICAL
        // 解析 XML 中的自定义属性
        context.obtainStyledAttributes(attrs, R.styleable.CustomRatingBar).apply {
            starCount = getInt(R.styleable.CustomRatingBar_starCount, 5)
            currentRating = getFloat(R.styleable.CustomRatingBar_rating, 0f)
            mRating = getFloat(R.styleable.CustomRatingBar_rating, 0f)
            starSpacing = getDimensionPixelSize(R.styleable.CustomRatingBar_starSpacing, 8)
            recycle()
        }
        initStars()
    }

    private fun initStars() {
        removeAllViews()
        for (i in 0 until starCount) {
            val star = ImageView(context).apply {
                layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT).apply {
                    if (i > 0) leftMargin = starSpacing
                }
                setOnClickListener { setRating((i + 1).toFloat()) }
            }
            addView(star)
            starViews.add(star)
        }
        updateStars()
    }

    fun setRating(rating: Float) {
        currentRating = rating.coerceIn(mRating, starCount.toFloat())
        updateStars()
    }

    private fun updateStars() {
        starViews.forEachIndexed { index, imageView ->
            //向左滑动最少显示指定的默认选中数量
            val resId = if (index < currentRating || (index==0&&currentRating==mRating)) R.mipmap.star_true else R.mipmap.star_false
            imageView.setImageResource(resId)
        }
    }

    // 支持手指滑动评分
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
                val newRating = (event.x / width * starCount).toInt() + 1
                setRating(newRating.toFloat())
                return true
            }
        }
        return super.onTouchEvent(event)
    }
}

3.xml中使用

XML 复制代码
	<LinearLayout
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/black"
            android:textSize="15dp"
            android:text="星级评分:"/>
        <CustomRatingBar
            android:id="@+id/customRatingBar"
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            app:starCount="5"
            app:rating="1"
            app:starSpacing="12dp"
            app:starEmpty="@mipmap/star_true"
            app:starFull="@mipmap/star_false" />
    </LinearLayout>

4.代码中获取当前选中几颗星

XML 复制代码
val choose = binding.customRatingBar.currentRating.toInt()

图片元素(效果图中使用的图片,可替换自己的)

相关推荐
古夕6 分钟前
第三方 SSO 接入实践:redirect_uri 编码、回调一致性与跨项目联调
前端·vue.js
朦胧之9 分钟前
页面白屏卡住排查方法
前端·javascript
用户593608741409 分钟前
Playwright 黑魔法:用 ClipboardEvent 绕过 React 富文本编辑器
前端
石山岭40 分钟前
自己动手写了一个 Android 虚拟定位 App:GPSSimulate 技术实
android·前端
犇驫聊AI1 小时前
Chrome DevTools MCP + Claude Code 自定义skills生成接口代码生成器
前端·javascript
kyriewen1 小时前
别再这样写 async/await 了:我在 Code Review 中见过最多的 8 个错误
前端·javascript·面试
hoLzwEge1 小时前
node-linker VS shamefully-hoist
前端·前端框架
袋鱼不重2 小时前
解决 Web 端图片预览与下载颜色不一致的一种工程方案
前端·后端
风止何安啊2 小时前
教你用 JS + AI 实现简单的爬虫,零门槛爬取网页信息
前端
cidy_982 小时前
codebase-memory-mcp 新手完全教程:让 AI 真正「理解」你的代码库
前端