Android 自定义星评空间示例代码
发布时间 - 2026-01-11 01:49:46 点击率:次没事做用自定义view方式写一个星评控件,虽说网上很多这个控件,但是这是自己写的,在这里记录一下。

首先需要自定义属性
<declare-styleable name="Rate">
<!--属性分别是:单个的宽,高,之间的距离,激活的数量,总数量,激活的drawable,没有激活的drawable,是否可以选择数量-->
<attr name="custom_rate_width" format="dimension"/>
<attr name="custom_rate_height" format="dimension"/>
<attr name="custom_rate_padding" format="dimension"/>
<attr name="custom_rate_active_size" format="integer"/>
<attr name="custom_rate_size" format="integer"/>
<attr name="custom_rate_active_drawable" format="reference"/>
<attr name="custom_rate_disactive_drawable" format="reference"/>
<attr name="custom_rate_touch" format="boolean"/>
</declare-styleable>
初始化代码
protected void init(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Rate);
int activeId = 0;
int disactiveId = 0;
if (array != null) {
size = array.getInt(R.styleable.Rate_custom_rate_size, 5);
activeSize = array.getInt(R.styleable.Rate_custom_rate_active_size, 3);
rateWidth = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_width, 0);
rateHeight = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_height, 0);
activeId = array.getResourceId(R.styleable.Rate_custom_rate_active_drawable, 0);
disactiveId = array.getResourceId(R.styleable.Rate_custom_rate_disactive_drawable, 0);
padding = array.getDimensionPixelOffset(R.styleable.Rate_custom_rate_padding, 0);
isTouch = array.getBoolean(R.styleable.Rate_custom_rate_touch, false);
array.recycle();
}
//如果没有宽高就设置一个默认值
if (rateHeight <= 0){
rateHeight = 80;
}
if (rateWidth <= 0){
rateWidth = 80;
}
if (activeId!=0){
activeBitmap = BitmapFactory.decodeResource(getResources(), activeId);
//如果没有设置宽高时候
if (rateWidth <= 0) {
rateWidth = activeBitmap.getWidth();
}
//把图片压缩到设置的宽高
activeBitmap = Bitmap.createScaledBitmap(activeBitmap, (int) rateWidth, (int) rateHeight, false);
}
if (disactiveId != 0){
disactiveBitmap = BitmapFactory.decodeResource(getResources(), disactiveId);
if (rateHeight <= 0) {
rateHeight = activeBitmap.getHeight();
}
disactiveBitmap = Bitmap.createScaledBitmap(disactiveBitmap, (int) rateWidth, (int) rateHeight, false);
}
mPaint = new Paint();//初始化bitmap的画笔
mPaint.setAntiAlias(true);
activPaint = new Paint();//初始化选中星星的画笔
activPaint.setAntiAlias(true);
activPaint.setColor(Color.YELLOW);
disactivPaint = new Paint();//初始化未选中星星的画笔
disactivPaint.setAntiAlias(true);
disactivPaint.setColor(Color.GRAY);
}
onMeasure方法设置View的宽高,如果设置的每一个星星控件的宽高大于实际view的宽高,就用星星空间的宽高作于view的宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//计算宽
if (widthMode == MeasureSpec.EXACTLY) {
//如果view的宽度小于设置size*星星的宽度,就用size * (int) (padding + rateWidth)做为控件的宽度度
if (widthSize < size * (int) (padding + rateWidth)) {
width = size * (int) (padding + rateWidth);
} else {
width = widthSize;
}
} else {
width = size * (int) (padding + rateWidth)-padding;
}
//计算高
if (heightMode == MeasureSpec.EXACTLY) {
//如果view的高度小于设置星星的高度,就用星星高度做为控件的高度
if (heightSize < rateHeight) {
height = (int) rateHeight + 5;
} else {
height = heightSize;
}
} else {
height = (int) rateHeight + 5;
}
setMeasuredDimension(width, height);
}
onDraw方法中绘制
//开始画active
for (int i = 0; i < activeSize; i++) {
if (activeBitmap != null){
if (i == 0) {
canvas.drawBitmap(activeBitmap, rateWidth * i, (height - rateHeight) / 2, mPaint);
} else {
canvas.drawBitmap(activeBitmap, (rateWidth + padding) * i, (height - rateHeight) / 2, mPaint);
}
}else {
drawActivRate(i,canvas);
}
}
// //开始画disactive
for (int i = activeSize; i < size; i++) {
if (disactiveBitmap != null){
if (i == 0) {
canvas.drawBitmap(disactiveBitmap, rateWidth * i, (height - rateHeight) / 2, mPaint);
} else {
canvas.drawBitmap(disactiveBitmap, (rateWidth + padding) * i, (height - rateHeight) / 2, mPaint);
}
}else {
drawDisActivRate(i,canvas);
}
}
上面用到两个方法drawActivRate和drawDisActivRate,分别是在没有设置活动中的星星和不在活动中星星的图片的时候,绘制在活动和不在活动的默认星星:
/**
* 绘制黄色的五角星(在活动的)
* */
private void drawActivRate(int position,Canvas canvas){
float radius = rateWidth/2;//根據每一個星星的位置繪製園,確定五角星五個點的位置
float angle = 360/5;
float centerX = (rateWidth+padding)*(position+1)-padding-radius;//獲取每一個星星空間的中心位置的X坐標
float centerY =height/2;//獲取每一個星星空間的中心位置的y坐標
Path mPath = new Path();
mPath.moveTo(centerX,centerY-radius);
mPath.lineTo(centerX+(float) Math.cos((angle*2-90)*Math.PI / 180)*radius,centerY+(float)Math.sin((angle*2-90)*Math.PI / 180)*radius);
mPath.lineTo( centerX-(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);
mPath.lineTo( centerX+(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);
mPath.lineTo( centerX-(float)Math.sin((angle*3-180)*Math.PI / 180)*radius,centerY+(float)Math.cos((angle*3-180)*Math.PI / 180)*radius);
// mPath.lineTo(centerX,centerY-radius);
mPath.close();
canvas.drawPath(mPath,activPaint);
}
/**
* 绘制灰色的五角星
* */
private void drawDisActivRate(int position,Canvas canvas){
float radius = rateWidth/2;
float angle = 360/5;
float centerX = (rateWidth+padding)*(position+1)-padding-radius;
float centerY =height/2;
Path mPath = new Path();
mPath.moveTo(centerX,centerY-radius);
mPath.lineTo(centerX+(float) Math.cos((angle*2-90)*Math.PI / 180)*radius,centerY+(float)Math.sin((angle*2-90)*Math.PI / 180)*radius);
mPath.lineTo( centerX-(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);
mPath.lineTo( centerX+(float)Math.sin(angle*Math.PI / 180)*radius,centerY-(float)Math.cos(angle*Math.PI / 180)*radius);
mPath.lineTo( centerX-(float)Math.sin((angle*3-180)*Math.PI / 180)*radius,centerY+(float)Math.cos((angle*3-180)*Math.PI / 180)*radius);
// mPath.lineTo(centerX,centerY-radius);
mPath.close();
canvas.drawPath(mPath,disactivPaint);
}
最后在onTouchEvent方法中处理选中和未选中星星的处理
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isTouch){//如果不支持觸摸
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchX = event.getX();
touchY = event.getY();
for (int i = 0; i < size; i++) {
if (i == 0) {
if (0.0 < touchX && touchX < rateWidth+padding/2) {
activeSize = 1;
}
}else {
if ((rateWidth+padding)*i-padding/2<touchX&&touchX<(rateWidth+padding)*(i+1)-padding/2){
activeSize = i+1;
}
}
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if ( null!= changeListener){
changeListener.change(activeSize);
}
break;
case MotionEvent.ACTION_MOVE:
touchX = event.getX();
touchY = event.getY();
for (int i = 0; i < size; i++) {
if (i == 0) {
if (0.0 < touchX && touchX < rateWidth+padding/2) {
activeSize = 1;
}
}else {
if ((rateWidth+padding)*i-padding/2<touchX&&touchX<(rateWidth+padding)*(i+1)-padding/2){
activeSize = i+1;
}
}
}
invalidate();
if (touchX<=0){
activeSize = 0;
}
break;
}
return true;
}
以上就是自定义view写的星评控件,代码中的注解已经比较详细了,就不多说了,
源码地址
以上所述是小编给大家介绍的android自定义星评空间的实例代码,希望对大家有所帮助!
# Android
# 自定义星评空间
# Android RatingBar星星评分控件实例代码
# Android UI控件RatingBar实现自定义星星评分效果
# Android自定义星星评分控件
# 自定义
# 就用
# 如果没有
# 这是
# 是在
# 在这里
# 活动中
# 说了
# 不多
# 给大家
# 不支持
# 可以选择
# 所述
# 小编
# 默认值
# 网上
# Rate_custom_rate_width
# rateWidth
# Rate_custom_rate_height
# Rate_custom_rate_active_drawable
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
高端云建站费用究竟需要多少预算?
php485函数参数是什么意思_php485各参数详细说明【介绍】
Thinkphp 中 distinct 的用法解析
Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践
Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
Laravel模型事件有哪些_Laravel Model Event生命周期详解
SQL查询语句优化的实用方法总结
Laravel如何与Pusher实现实时通信?(WebSocket示例)
如何用低价快速搭建高质量网站?
Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】
怎样使用JSON进行数据交换_它有什么限制
CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】
Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作
怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?
javascript如何操作浏览器历史记录_怎样实现无刷新导航
Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布
制作电商网页,电商供应链怎么做?
Laravel定时任务怎么设置_Laravel Crontab调度器配置
ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集
Laravel用户认证怎么做_Laravel Breeze脚手架快速实现登录注册功能
googleplay官方入口在哪里_Google Play官方商店快速入口指南
Laravel如何升级到最新的版本_Laravel版本升级流程与兼容性处理
html5的keygen标签为什么废弃_替代方案说明【解答】
Laravel distinct去重查询_Laravel Eloquent去重方法
laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法
如何在IIS中新建站点并解决端口绑定冲突?
微信小程序制作网站有哪些,微信小程序需要做网站吗?
使用PHP下载CSS文件中的所有图片【几行代码即可实现】
Laravel Octane如何提升性能_使用Laravel Octane加速你的应用
b2c电商网站制作流程,b2c水平综合的电商平台?
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
Laravel如何为API编写文档_Laravel API文档生成与维护方法
Linux系统命令中tree命令详解
Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】
百度输入法ai组件怎么删除 百度输入法ai组件移除工具
中国移动官方网站首页入口 中国移动官网网页登录
网站建设整体流程解析,建站其实很容易!
如何快速搭建高效简练网站?
焦点电影公司作品,电影焦点结局是什么?
Laravel怎么进行浏览器测试_Laravel Dusk自动化浏览器测试入门
网站图片在线制作软件,怎么在图片上做链接?
如何快速搭建虚拟主机网站?新手必看指南
移动端脚本框架Hammer.js
JS经典正则表达式笔试题汇总
学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?
javascript中的数组方法有哪些_如何利用数组方法简化数据处理

