自定义CustomRatingBar控件

news2024/9/22 7:34:10

通过自定义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 指示器。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1974119.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机毕业设计选题推荐-健康饮食系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

【优秀python 数据分析案例】基于python的穷游网酒店数据采集与可视化分析的设计与实现

1 需求分析 1.1 用户需求 1.1.1 背景与现状 穷游网是国内知名的旅游社区&#xff0c;在其网站上&#xff0c;用户可以自由分享旅行经验和攻略&#xff0c;也可以浏览其他用户的经验和攻略&#xff0c;以便更好地规划自己的旅行。而酒店信息是旅行攻略中不可或缺的一部分&#…

正点原子imx6ull-mini-Linux驱动之设备树下的 platform 驱动编写(15)

上一章我们详细的讲解了 Linux 下的驱动分离与分层&#xff0c;以及总线、设备和驱动这样的驱动 框架。基于总线、设备和驱动这样的驱动框架&#xff0c;Linux 内核提出来 platform 这个虚拟总线&#xff0c;相应 的也有 platform 设备和 platform 驱动。上一章我们讲解了传统的…

vue2学习 -- 脚手架

文章目录 1. 使用2. render函数3. vue.config.js配置文件4. ref属性5. props配置6. mixin7. 插件8. scoped 1. 使用 脚手架文档 安装脚手架 npm install -g vue/cli 选择工作目录&#xff0c;创建项目 vue create name 2. render函数 关于不同版本的Vue.js vue.js与vue.run…

在 VueJS 项目中实现多个可拖拽的弹出框(多个可拖拽el-dialog弹出框,共用同一函数)

前言 在项目开发中&#xff0c;弹出框&#xff08;Dialog&#xff09;是常见的UI组件。默认情况下&#xff0c;弹出框的位置是固定的&#xff0c;但在某些场景下&#xff0c;我们希望用户可以自由拖动弹出框的位置&#xff0c;以提升用户体验。之前单个视频拖拽弹框&#xff0…

Spring Boot 参数校验 Validation 使用

概述 当我们想提供可靠的 API 接口&#xff0c;对参数的校验&#xff0c;以保证最终数据入库的正确性&#xff0c;是必不可少的活。前、后端校验都是保证参数的准确性的手段之一&#xff0c;前端校验并不安全&#xff0c;任何人都可以通过接口来调用我们的服务&#xff0c;就算…

springboot电影购票系统-计算机毕业设计源码85384

目录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1系统开发流程 2.2.2 用户登录流程 2.2.3 系统操作流程 2.2.4 添加信息流程 2.2.5 修改信息流程 2.2.6 删除信息流程 2.3 系统功能…

ComfyUI插件:ComfyUI layer style 节点(三)

前言&#xff1a; 学习ComfyUI是一场持久战&#xff0c;而ComfyUI layer style 是一组专为图片设计制作且集成了Photoshop功能的强大节点。该节点几乎将PhotoShop的全部功能迁移到ComfyUI&#xff0c;诸如提供仿照Adobe Photoshop的图层样式、提供调整颜色功能&#xff08;亮度…

哪里可以找到数据恢复软件?5 款顶级数据恢复软件分享

在当今的数字时代&#xff0c;我们的数据既是我们最宝贵的资产&#xff0c;也是我们最大的弱点。由于硬件故障、意外删除或软件问题&#xff0c;丢失重要文档、珍贵照片或对职业至关重要的项目的风险始终存在。值得庆幸的是&#xff0c;强大的数据恢复软件可以帮助找回最初看似…

[每周一更]-(第108期):如何保护你的JavaScript代码

文章目录 一、框架如何实现JS的保护1. 模块化和组件化2. 使用环境变量3. 代码混淆和最小化vue.config.js 4. 使用请求库和拦截器axios.js 文件在组件中使用 Axios 拦截器 5. 服务端处理敏感逻辑6. 安全最佳实践使用 CSP 7. 依赖前端框架的内置安全特性8. 数据验证和清理 二、原…

【linux】【操作系统】内核之traps.c源码阅读

C 文件traps.c 是 Linux 内核的一部分&#xff0c;主要处理硬件陷阱和故障。文件中包含多个函数来处理不同类型的异常和错误。下面是详细的解析&#xff1a; 概览 目的&#xff1a;此文件负责处理各种硬件异常和故障。它包括了处理特定类型错误以及初始化异常处理器的函数。文…

uniapp0基础编写安卓原生插件和调用第三方jar包(Ch34的jar包)和如何解决android 如何Application初始化

前言 我假设你会uniapp安卓插件开发了,如果不会请看这篇文章,这篇文章是0基础教学。 这篇文章我们将讲一下如何使用CH34XUARTDriver.jar进行开发成uniapp插件。 它的难点是:uniapp如何Application初始化第三方jar包 先去官网下载CH340/CH341的USB转串口安卓免驱应用库:h…

Spring实现自定义注解

一&#xff0c; 背景 目前部门有一个培训&#xff0c;需要讲一下Spring的使用&#xff0c;看到有同学提出问题&#xff0c;想自定义实现一个打日志的注解&#xff0c;下面就记录一下实现过程。 环境&#xff1a; Spring 6.1.5, 不使用Spring Boot. 二&#xff0c;实现步骤 …

Mysql--权限与安全管理

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、权限表 MySQL服务器通过权限表来控制用户对数据库的访问&#xff0c;权限表存放在MySQL数据库中&#xff0c;由MySQL_install_db脚本初始化。存储…

【工具篇】华为VRP通用操作系统 —— 配置文件管理

文章目录 配置文件分类配置文件命令配置文件工作原理 配置文件分类 设备的配置文件通常有两种类型&#xff1a; 1、启动配置文件&#xff08;Startup Configuration&#xff09;&#xff1a; 这是设备启动时加载的配置文件&#xff0c;包含了设备的基本配置信息&#xff0c;如…

Linux 内核源码分析---资源分配及系统总线

资源管理 Linux提供通用的构架&#xff0c;用于在内存中构建数据结构。这些结构描述了系统中可用的资源&#xff0c;使得内核代码能够管理和分配资源。 其中关键的数据结构resource如下&#xff1a; 用于连接parent, child, sibling成员规则如下&#xff1a; 1、每个子结点只…

接口测试学习笔记1

一、行业背景和测试分层 1、招聘需求 1&#xff09;手工测试&#xff1a;业务需求、业务逻辑 2&#xff09;自动化测试&#xff1a;业务逻辑 技术规范 功能自动化 QTP、Selenium 性能自动化 LoadRunner、JMeter 接口自动化 Postman、Fiddler、JMeter、SoapUI... …

值得一读!六本网络安全学习必备书籍推荐

在网络安全领域不断发展的今天&#xff0c;深入学习和掌握相关知识显得尤为重要。以下为大家推荐六本有助于提升网络安全技能的经典书籍。 一、《白帽子讲 Web 安全》 这本书由吴翰清撰写&#xff0c;涵盖了 Web 安全的诸多方面&#xff0c;包括常见的攻击手段、防御方法以及安…

XML 学习笔记

简介&#xff1a; &#xff08;1&#xff09;XML&#xff1a;可扩展性标记语言&#xff0c;用于传输和存储数据&#xff0c;而不是展示数据&#xff0c;是W3C 推举的数据传输格式。 XML的标签必须自定义&#xff0c;但是在写标签名的时候一定要有含义。 XML 只能有一个根节点…

微积分-微分应用7(优化问题)

解决优化问题的步骤&#xff1a; 理解问题 首先要仔细阅读问题&#xff0c;直到完全理解。问问自己&#xff1a;未知数是什么&#xff1f;已知量是什么&#xff1f;给定的条件是什么&#xff1f; 画图 在大多数问题中&#xff0c;画图并在图中标出给定和所需的量是有用的。 引…