一个简单易用的RatingBar
前几天需要做一个评星的功能,于是先尝试了一下系统自带的RatingBar,但是使用的时候发现,在手机上很容易误点!比如我想点4星,结果很容易点中5星。另外一个问题是星星之间的间距是不能设置的,于是到GitHub上找,发现有的效果做得很好看,但是还是无法解决容易误点的问题,于是打算自定义一个。
先上一个效果图
需求
先说一下我的需要:
- 不易引起误点操作
- 支持修改颜色(选中和未选中的颜色)
- 不需要像系统自带的RatingBar那样支持拖动
- 支持设置星星总数和大小
- 支持设置星星之间的间距
实现
有了需求之后就开始考虑实现的步骤:
- 创建自定义的属性
- 实现View的子类,重写onMeasure、onDraw等方法
首先是属性定义:在res/value目录下创建一个attrs.xml文件,并添加以下的属性,
解释一下starType属性,考虑到有的场景可能会用到心形,所以定义这个属性来决定评星是星星的形状还是心形。
<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="SimpleRatingView"><attr name="starType" format="enum"><enum name="star" value="1"/><enum name="heart" value="2"/></attr><attr name="starSize" format="dimension" /><attr name="starSpacing" format="dimension" /><attr name="numStars" format="integer" /><attr name="rating" format="integer" /><attr name="primaryColor" format="color" /><attr name="secondaryColor" format="color" /></declare-styleable>
</resources>
创建一个类继承View类,重写onMeasure、onDraw方法:
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int paddingLeft = getPaddingLeft();int paddingRight = getPaddingRight();int paddingTop = getPaddingTop();int paddingBottom = getPaddingBottom();int width = (int) (paddingLeft + paddingRight + starSize * numStars + starSpacing * (numStars - 1));int height = (int) (paddingTop + paddingBottom + starSize);setMeasuredDimension(width, height);}@Overrideprotected void onDraw(Canvas canvas) {int paddingLeft = getPaddingLeft();int paddingTop = getPaddingTop();// 以24为基准做缩放float scale = starSize / 24;// 校正参数if (numStars <= 0) {throw new IllegalArgumentException("numStars不能小于等于0");}if (rating < 0) {rating = 0;}if (rating > numStars) {rating = numStars;}// 先绘制primaryColor的星星for (int i = 0; i < numStars; i++) {if (i < rating) {paint.setColor(primaryColor);} else {paint.setColor(secondaryColor);}canvas.save();canvas.translate(paddingLeft + (starSize + starSpacing) * i, paddingTop);path.reset();if (starType == STAR) {// 星星path.moveTo(scale * 12f, scale * 17.27f);path.lineTo(scale * 18.18f, scale * 21f);path.rLineTo(scale * -1.64f, scale * -7.03f);path.lineTo(scale * 22f, scale * 9.24f);path.rLineTo(scale * -7.19f, scale * -0.61f);path.lineTo(scale * 12f, scale * 2f);path.lineTo(scale * 9.19f, scale * 8.63f);path.lineTo(scale * 2f, scale * 9.24f);path.rLineTo(scale * 5.46f, scale * 4.73f);path.lineTo(scale * 5.82f, scale * 21f);path.close();} else if (starType == HEART) {// 心形path.moveTo(scale * 12f,scale * 21.35f);path.rLineTo(scale * -1.45f,scale * -1.32f);path.cubicTo(scale * 5.4f,scale * 15.36f,scale * 2f,scale * 12.28f,scale * 2f,scale * 8.5f);path.cubicTo(scale * 2f,scale * 5.42f, scale * 4.42f,scale * 3f, scale * 7.5f,scale * 3f);path.rCubicTo(scale * 1.74f,scale * 0f, scale * 3.41f,scale * 0.81f, scale * 4.5f,scale * 2.09f);path.cubicTo(scale * 13.09f,scale * 3.81f, scale * 14.76f,scale * 3f, scale * 16.5f,scale * 3f);path.cubicTo(scale * 19.58f,scale * 3f, scale * 22f,scale * 5.42f, scale * 22f,scale * 8.5f);path.rCubicTo(scale * 0f,scale * 3.78f, scale * -3.4f,scale * 6.86f, scale *-8.55f,scale * 11.54f);path.lineTo(scale * 12f,scale * 21.35f);path.close();} else {}canvas.drawPath(path, paint);canvas.restore();}}
另外还需要重写一个重要的方法onTouchEvent,我们需要在这个方法中判断点击的位置,这样才能知道点中的是第几个星星,我们也可以在这个方法去设置点击的有效范围
@Overridepublic boolean onTouchEvent(MotionEvent event) {float dx = event.getX();float dy = event.getY();int paddingLeft = getPaddingLeft();int paddingTop = getPaddingTop();int oldRating = rating;int newRating = rating;float dxx;boolean isClick = false;// 计算点击事件产生在哪个星星上if (dy > paddingTop && dy <= paddingTop + starSize) {for (int i = 1; i <= numStars; i++) {dxx = dx - paddingLeft - (starSize + starSpacing) * (i - 1);if (dxx > 0 && dxx < starSize) {newRating = i;isClick = true;break;}}}int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:if (isClick) {setRating(newRating);if (onRatingChangeListener != null) {onRatingChangeListener.onRatingChange(oldRating, newRating);}}break;case MotionEvent.ACTION_UP:performClick();break;}return true;}
最后再加上一个回调事件接口:
public interface OnRatingChangeListener {void onRatingChange(int oldRating, int newRating);}
GitHub地址
该项目已经开源到GitHub上了,可以点击这里跳转
一个简单易用的RatingBar相关推荐
- idea log 不输出error_还在使用console.log()吗?Bunyan:一个简单易用的JS日志框架
Bunyan是一个简单易用的JS日志框架,可以工作在多种环境下,这里以Nodejs为例说明Bunyan的基本用法.是时候替换console.log的写法了. 安装 npm install --save ...
- 基于ForkJoin构建一个简单易用的并发组件
2019独角兽企业重金招聘Python工程师标准>>> 基于ForkJoin构建一个简单易用的并发组件 在实际的业务开发中,需要用到并发编程的知识,实际使用线程池来异步执行任务的场景 ...
- 开发一个简单易用的SDK的详细步骤(超详细,超适用)
文章目录 开发一个简单易用的SDK的详细步骤 创建starter步骤 关键点 总结 开发一个简单易用的SDK的详细步骤 创建starter步骤 1.新建一个 spring boot 初始化项目 2.添 ...
- easyopen——一个简单易用的接口开放平台
摘要: 一个简单易用的接口开放平台,平台封装了常用的参数校验.结果返回等功能,开发者只需实现业务代码即可. easyopen介绍 一个简单易用的接口开放平台,平台封装了常用的参数校验.结果返回等功能, ...
- d3.js 旋转图形_一个简单易用但功能强大的图形矢量化软件,扫描图片转换成CAD图的软件等等...
背景简介 很多童鞋可能可能有想要把图片转成CAD能打开的格式,但是找不到软件,今天要分享的这个软件值得一试. 内容简介 AlgoLabR2VToolkit是一个将光栅图像转换为矢量图像的软件,转换后的 ...
- 如何选择一个简单易用的云桌面
如何选择一个简单易用的企业级桌面云系统 废话少说,服务器虚拟化相信大家都熟悉了,也没啥难度了:但是桌面虚拟化就没那们简单.给你看一个Horizon View的系统架构,复杂不?反正一个新手,不折腾个把 ...
- python 消息队列 go_gmq: gmq是基于redis提供的特性,使用go语言开发的一个简单易用的消息队列;支持延迟任务,异步任务,超时任务,优先级任务...
1. 概述 gmq是基于redis提供的特性,使用go语言开发的一个简单易用的队列;关于redis使用特性可以参考之前本人写过一篇很简陋的文章Redis 实现队列; gmq的灵感和设计是基于有赞延迟队 ...
- Qt怎么实现将bmp图片转换成Ascii_一个简单易用但功能强大的图形矢量化软件,扫描图片转换成CAD图的软件等等...
背景简介 很多童鞋可能可能有想要把图片转成CAD能打开的格式,但是找不到软件,今天要分享的这个软件值得一试. 内容简介 AlgoLabR2VToolkit是一个将光栅图像转换为矢量图像的软件,转换后的 ...
- java通讯框架_gim: 一个简单易用,稳定高效的及时通讯框架(java、android)
gim 一个简单易用,稳定高效的及时通讯框架(java) 简介: gim是基于高性能网络框架getty封装的,能简单上手,稳定高效的及时通讯框架 Getty:[https://github.com/g ...
最新文章
- Django celery6.4
- django 完整日志配置
- linux下命令行打开文件管理器
- 1-编程的基本条件和起步
- jQuery 事件用法详解
- golang panic的错误回收和简单的使用场景
- [Leedcode][JAVA][第9题][回文数][数学法]
- 【刷算法】字符串的全排列
- 安川机器人位置变量要素_安川机器人变量分配(维修)
- 区块链溯源系统架构---区块链工作笔记002
- oracle配置ipv6_配置 IPv6 接口
- jquery判断页面标签是否存在
- 没想到,这么简单的线程池用法,深藏这么多坑!
- vasp服务器中断,vasp优化结构没提示直接中断
- 动易cms5.0如何安装在远程服务器上,动易PowerEasy_SiteWeaver_CMS6.8安装教程
- Javascript回显图片
- java 其他文件转pdf_java 其他文件转成pdf java生成pdf
- 小米扫地机器人漏灰_#原创新人#一次失败的改装:MI 小米 扫地机器人 改装湿拖功能...
- linux下安装虚拟天文馆,【地理软件】虚拟天文馆——stellarium
- 输入一个四位数字x,分别求出x的个位数字、十位数字、百位数字和千位数字的值 ,并求个位、十位、百位、千位的和 -C语言
热门文章
- play(三) play实例项目开发Yabe 2前端页面
- JS代码在线优化工具
- 2019年牛市第一波技术指标选股神器组合源码
- qq修改实名认证已达上限_英雄联盟健康系统实名认证修订指引
- Tikmeta分享 |达人营销,你知道多少?
- CISA Cert Prep: 5 Information Asset Protection for IS Auditors CISA证书准备:5 IS审计员的信息资产保护 Lynda课程中文字幕
- WIN10不能安装S7-200的解决方法
- 【说说你和异性同桌干过的最浪漫的事 】 ----看到第176楼就突然沉默了....(节选自百度DotA吧)...
- VC++实现视频聊天:FFmpeg解码+SDL播放视频
- 【定义】矩阵初等变换和矩阵等价