Android开发中,经常要实现星星的评分效果如下图,所以今天就记录下来,以便他人使用。

1、自定义RatingBar代码:

package com.example.myapplicationtest;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;/*** @author* @package* @desc 评星* @date 2019/7/05 18:44* @copyright* @company*/
public class RatingBar extends View {private static final String TAG = "AirRatingBar";/*** 默认,半个,全部选中*/private Bitmap mRatingNormal, mRatingHalf, mRatingSelected;/*** 总数*/private int mRatingTotalNum = 5;/*** 选中的数量*/private float mRatingSelectedNumber;/*** 是否画全部*/private Status status = Status.FULL;/*** 是否画全部* true 画全部* false 画半个*/private boolean isFull;/*** 状态变化监听*/private OnStarChangeListener mOnStarChangeListener;/*** 画笔*/private Paint mPaint;/*** 间距*/private int mRatingDistance;/*** 宽和高*/private float mRatingWidth;private float mRatingHeight;/*** 是否可选中*/private boolean selectable;public RatingBar(Context context) {this(context, null);}public RatingBar(Context context, AttributeSet attrs) {this(context, attrs, 0);}public RatingBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initPaint();initTypeArray(context, attrs);}/*** 画笔*/private void initPaint() {mPaint = new Paint();}/*** 属性** @param context* @param attrs*/private void initTypeArray(Context context, AttributeSet attrs) {TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.AirRatingBar);// 未选中的图片资源int starNormalId = array.getResourceId(R.styleable.AirRatingBar_ratingDefault, 0);if (starNormalId == 0) {throw new IllegalArgumentException("请设置属性 starNormal");}mRatingNormal = getBitmap(context, starNormalId);// 选中一半的图片资源int starHalfId = array.getResourceId(R.styleable.AirRatingBar_ratingHalf, 0);if (starHalfId != 0) {mRatingHalf = getBitmap(context, starHalfId);}// 选中全部的图片资源int starSelectedId = array.getResourceId(R.styleable.AirRatingBar_ratingSelect, 0);if (starSelectedId == 0) {throw new IllegalArgumentException("请设置属性 starSelected");}mRatingSelected = getBitmap(context, starSelectedId);// 如果没设置一半的图片资源,就用全部的代替if (starHalfId == 0) {mRatingHalf = mRatingSelected;}mRatingTotalNum = array.getInt(R.styleable.AirRatingBar_ratingTotalNum, mRatingTotalNum);mRatingSelectedNumber = array.getFloat(R.styleable.AirRatingBar_ratingDefaultSelectNum, mRatingSelectedNumber);mRatingDistance = (int) array.getDimension(R.styleable.AirRatingBar_ratingDistance, 0);mRatingWidth = array.getDimension(R.styleable.AirRatingBar_ratingWidth, 0);mRatingHeight = array.getDimension(R.styleable.AirRatingBar_ratingHeight, 0);isFull = array.getBoolean(R.styleable.AirRatingBar_ratingIsFull, true);selectable = array.getBoolean(R.styleable.AirRatingBar_ratingSelectable, false);array.recycle();// 如有指定宽高,获取最大值 去改变星星的大小(星星是正方形)int starWidth = (int) Math.max(mRatingWidth, mRatingHeight);if (starWidth > 0) {mRatingNormal = resetBitmap(mRatingNormal, starWidth);mRatingSelected = resetBitmap(mRatingSelected, starWidth);mRatingHalf = resetBitmap(mRatingHalf, starWidth);}// 计算一半还是全部(小数部分小于等于0.5就只是显示一半)if (!isFull) {int num = (int) mRatingSelectedNumber;if (mRatingSelectedNumber <= (num + 0.5f)) {status = Status.HALF;}}}@Overrideprotected void onDraw(Canvas canvas) {// 循环绘制for (int i = 0; i < mRatingTotalNum; i++) {float left = getPaddingLeft();// 从第二个星星开始,给它设置星星的间距if (i > 0) {left = getPaddingLeft() + i * (mRatingNormal.getWidth() + mRatingDistance);}float top = getPaddingTop();// 绘制选中的星星if (i < mRatingSelectedNumber) {// 比当前选中的数量小if (i < mRatingSelectedNumber - 1) {canvas.drawBitmap(mRatingSelected, left, top, mPaint);} else {// 在这里判断是不是要绘制满的if (status == Status.FULL) {canvas.drawBitmap(mRatingSelected, left, top, mPaint);} else {canvas.drawBitmap(mRatingHalf, left, top, mPaint);}}} else {// 绘制正常的星星canvas.drawBitmap(mRatingNormal, left, top, mPaint);}}}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (!selectable) {return super.onTouchEvent(event);}//减少绘制if (event.getAction() == MotionEvent.ACTION_MOVE) {// 获取用户触摸的x位置float x = event.getX();// 一个星星占的宽度int startWidth = getWidth() / mRatingTotalNum;// 计算用户触摸星星的位置int position = (int) (x / startWidth + 1);if (position < 0) {position = 0;}if (position > mRatingTotalNum) {position = mRatingTotalNum;}Status statu = Status.FULL;// 结果大于一半就是满的if (!isFull) {if ((mRatingSelectedNumber * 10) % 10 > 0 && (mRatingSelectedNumber * 10) % 10 <= 5) {statu = Status.HALF;}}//减少绘制if (mRatingSelectedNumber != position || statu != status) {mRatingSelectedNumber = position;status = statu;invalidate();if (mOnStarChangeListener != null) {position = (int) (mRatingSelectedNumber - 1);// 选中的数量回调float selectedNumber = status == Status.FULL ? mRatingSelectedNumber: (mRatingSelectedNumber - 0.5f);mOnStarChangeListener.onStarChanged(selectedNumber,position < 0 ? 0 : position);}}} else if (event.getAction() == MotionEvent.ACTION_DOWN) {// 获取用户触摸的x位置float x = event.getX();// 一个星星占的宽度int startWidth = getWidth() / mRatingTotalNum;// 计算用户触摸星星的位置int position = (int) (x / startWidth + 1);if (position < 0) {position = 0;}if (position > mRatingTotalNum) {position = mRatingTotalNum;}Status statu = Status.FULL;// 结果大于一半就是满的if (!isFull) {if ((mRatingSelectedNumber * 10) % 10 > 0 && (mRatingSelectedNumber * 10) % 10 <= 5) {statu = Status.HALF;}}//减少绘制if (mRatingSelectedNumber != position || statu != status) {mRatingSelectedNumber = position;status = statu;invalidate();if (mOnStarChangeListener != null) {position = (int) (mRatingSelectedNumber - 1);// 选中的数量回调float selectedNumber = status == Status.FULL ? mRatingSelectedNumber: (mRatingSelectedNumber - 0.5f);mOnStarChangeListener.onStarChanged(selectedNumber,position < 0 ? 0 : position);}}}return true;}/*** 如果用户设置了图片的宽高,就重新设置图片*/public Bitmap resetBitmap(Bitmap bitMap, int startWidth) {// 得到新的图片return Bitmap.createScaledBitmap(bitMap, startWidth, startWidth, true);}/*** 设置选中星星的数量*/public void setSelectedNumber(int selectedNumber) {if (selectedNumber >= 0 && selectedNumber <= mRatingTotalNum) {this.mRatingSelectedNumber = selectedNumber;invalidate();}}/*** 设置星星的总数量*/public void setStartTotalNumber(int startTotalNumber) {if (startTotalNumber > 0) {this.mRatingTotalNum = startTotalNumber;invalidate();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 用正常的一个星星图片去测量高int height = getPaddingTop() + getPaddingBottom() + mRatingNormal.getHeight();// 宽 = 星星的宽度*总数 + 星星的间距*(总数-1) +paddingint width = getPaddingLeft() + getPaddingRight() + mRatingNormal.getWidth() * mRatingTotalNum + mRatingDistance * (mRatingTotalNum - 1);setMeasuredDimension(width, height);}/*** 获得bitmap** @param context* @param vectorDrawableId* @return*/private Bitmap getBitmap(Context context, int vectorDrawableId) {Bitmap bitmap;if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {Drawable vectorDrawable = context.getDrawable(vectorDrawableId);bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());vectorDrawable.draw(canvas);} else {bitmap = BitmapFactory.decodeResource(context.getResources(), vectorDrawableId);}return bitmap;}public boolean isSelectable() {return selectable;}public void setSelectable(boolean selectable) {this.selectable = selectable;}private enum Status {/*** 全部 or 半个*/FULL, HALF}public void setOnStarChangeListener(OnStarChangeListener onStarChangeListener) {mOnStarChangeListener = onStarChangeListener;}public interface OnStarChangeListener {/***  状态变化回调* @param selectedNumber 选择数量* @param position       position*/void onStarChanged(float selectedNumber, int position);}
}

2、drawable下 svg_star_c126文件

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="1024"android:viewportHeight="1024"><pathandroid:fillColor="@color/c126"android:pathData="M512,768l196.27,81.07c29.87,12.8 59.73,-8.53 59.73,-42.67l-17.07,-209.07 140.8,-157.87c21.33,-25.6 8.53,-59.73 -21.33,-68.27l-204.8,-46.93L554.67,145.07c-17.07,-25.6 -55.47,-25.6 -72.53,0L366.93,328.53 162.13,375.47c-29.87,8.53 -42.67,42.67 -21.33,68.27l140.8,157.87 -17.07,209.07c-4.27,29.87 29.87,55.47 59.73,42.67l187.73,-85.33z" />
</vector>

3、drawable下 svg_star_c201.xml文件

<vector xmlns:android="http://schemas.android.com/apk/res/android"android:width="24dp"android:height="24dp"android:viewportWidth="1024"android:viewportHeight="1024"><pathandroid:fillColor="@color/c201"android:pathData="M512,768l196.27,81.07c29.87,12.8 59.73,-8.53 59.73,-42.67l-17.07,-209.07 140.8,-157.87c21.33,-25.6 8.53,-59.73 -21.33,-68.27l-204.8,-46.93L554.67,145.07c-17.07,-25.6 -55.47,-25.6 -72.53,0L366.93,328.53 162.13,375.47c-29.87,8.53 -42.67,42.67 -21.33,68.27l140.8,157.87 -17.07,209.07c-4.27,29.87 29.87,55.47 59.73,42.67l187.73,-85.33z" />
</vector>

4、color.xml

<color name="c201">#ffa516</color>
<color name="c126">#bdbdbd</color>

5、attrs.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="DatePickerView"><attr name="picker_model" format="string" /><!--模式--></declare-styleable><declare-styleable name="BackdropInput"><attr name="input_enable" format="boolean" /><attr name="left_icon" format="reference" /><attr name="input_hint" /></declare-styleable><declare-styleable name="WithTitleInput"><attr name="input_icon" format="reference" /><!--图标--><attr name="input_hint" /></declare-styleable><attr name="input_hint" format="string" /><!--hint--><declare-styleable name="ItemView"><attr name="style" format="string" /><attr name="text1" format="string" /><attr name="text2" format="string" /></declare-styleable><attr name="cbd_calendar_row" format="integer" /><declare-styleable name="CalendarDateView"><attr name="cbd_calendar_row" /></declare-styleable><declare-styleable name="FeatureItemView"><attr name="feature_style" format="string" /><attr name="text_left_hint" format="string" /><attr name="text_left" format="string" /><attr name="text_right_hint" format="string" /><attr name="text_right" format="string" /><attr name="image_right" format="reference" /></declare-styleable><declare-styleable name="SubtitleItemView"><attr name="subtitle_style" format="string" /><attr name="left_text" format="string" /></declare-styleable><declare-styleable name="ExpandRcv"><attr name="title" format="string" /></declare-styleable><declare-styleable name="AirRatingBar"><!--未选中--><attr name="ratingDefault" format="reference" /><!--选中半个--><attr name="ratingHalf" format="reference" /><!--选中--><attr name="ratingSelect" format="reference" /><!--总数--><attr name="ratingTotalNum" format="integer" /><!--默认选中的数量 --><attr name="ratingDefaultSelectNum" format="float" /><!--间距--><attr name="ratingDistance" format="dimension" /><!--宽度--><attr name="ratingWidth" format="dimension" /><!--高度--><attr name="ratingHeight" format="dimension" /><!--整个 or 半个--><attr name="ratingIsFull" format="boolean" /><!--是否可选中--><attr name="ratingSelectable" format="boolean" /></declare-styleable>
</resources>

6、布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="16dp"android:text="xxxxxx" /><TextViewandroid:id="@+id/tv_state"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="end"android:layout_marginRight="8dp"android:layout_toLeftOf="@+id/rb_test"android:text="请评价" /><com.example.myapplicationtest.RatingBarandroid:id="@+id/rb_test"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginRight="16dp"app:ratingDefault="@drawable/svg_star_c126"app:ratingDefaultSelectNum="0"app:ratingDistance="4dp"app:ratingIsFull="true"app:ratingSelect="@drawable/svg_star_c201"app:ratingSelectable="true"app:ratingTotalNum="5"/></RelativeLayout>

7、Activity类

rb_test.setOnStarChangeListener { selectedNumber, position ->if (1.0F==selectedNumber) {tv_state.setText("非常不满意");} else if (2.0F == selectedNumber) {tv_state.setText("不满意");} else if (3.0F == selectedNumber) {tv_state.setText("一般");} else if (4.0F == selectedNumber) {tv_state.setText("满意");} else if (5.0F == selectedNumber) {tv_state.setText("非常满意");}}
 

Android 自定义RatingBar实现相关推荐

  1. Android 自定义RatingBar设置步长没起作用

    在项目中使用到了RatingBar控件,在自定义RatingBar的样式后,设置stepSize 没起作用. <RatingBarandroid:id="@+id/ratingBar& ...

  2. android 星级评论,Android自定义RatingBar(星级评分控件)

    1.首先在Drawable下建立five_rating_bar.xml android:id="@android:id/background" android:drawable=& ...

  3. Android中RatingBar的自定义效果

    Android中RatingBar的自定义效果 有时候android系统提供给我们的ratingbar效果并不达到我们的要求,这个时候就可以自定义自己喜欢的ratingbar. 从上面的效果可以看出, ...

  4. 【Android自定义View实战】之自定义评价打分控件RatingBar,可以自定义星星大小和间距...

    [Android自定义View实战]之自定义评价打分控件RatingBar,可以自定义星星大小和间距

  5. Android中自定义RatingBar实现星星大小,数量,间距等的设置

    前言   系统中自带的RatingBar使用起来非常不方便,并且无法调整合适大小,于是自定义一个可自己调节星星数量,大小,间距等属性的RatingBar Demo展示图片: 布局代码如下: //(la ...

  6. android ratingbar样式,自定义RatingBar的样式

    写星座运势,难免要写RatingBar. 用法: 1.属性 android:numStars : 星星个数 android:rating : 默认点亮的星星星星个数 android:stepSize  ...

  7. android自定义对话框_Android自定义提醒对话框

    android自定义对话框 In this tutorial, we'll be discussing and implementing Custom Alert Dialogs in our And ...

  8. android 自定义音量调节,Android——自定义音量调节控件

    今天我们要实现一个上图中音量调节的效果.主要有两种实现方式自定义RatingBar和自定义View. 自定义RatingBar volume_rating.xml main.xml android:i ...

  9. Android自定义ViewGroup基本步骤

    1.自定义属性,获取自定义属性,可参考 ​ Android自定义View基本步骤 ​ 2.onMeasure() 方法,for循环测量子View,根据子View的宽高来计算自己的宽 高 3.onDra ...

最新文章

  1. 外观模式coding
  2. 在win10 或者win7系统下装双系统ubuntu16.04教程
  3. c++局部对象是什么_程序员每日一题-GCROOT对象
  4. java高并发临时表_不适用临时表进行分页,筛选,查询,避免高并发的方法。...
  5. java sleep 循环_while循环中的Thread.sleep()
  6. 编程学习记录1:编程的一些简单概念
  7. c++对象的生命周期
  8. Unity学习笔记(二)——Unity ML-agents安装与配置(1.9.1)
  9. IDEA 插件开发 - 创建自定义私有仓库
  10. windows下运行bochs
  11. 无向图的邻接表表示法
  12. 历史库存sap_SAP历史库存MB5B的详解
  13. 利用LSTM自动生成中文文本
  14. 【nowcoder 110246】Dima and Salad
  15. linux设置用户密码
  16. [数据库原理] 事务的隔离等级 (ANSI标准)
  17. uniapp H5 实现地图选址功能
  18. CSGO开箱C++小程序。(229行)
  19. Crane: 腾讯开源一款基于 FinOps 超强大云资源分析与成本优化平台
  20. 计算机图形学 OpenGl-种子填充算法画红黄绿交通灯

热门文章

  1. 实用计算机理论基础知识试题及答案,计算机基础知识试题及答案(1)
  2. PYTHON DJANGO开发工资查询系统
  3. 测试屈光度软件,家长们看过来,还可以这样监测孩子的视力
  4. RUST——互斥锁的使用
  5. 软件机器人加持财务共享服务中心,助力企业财务转型
  6. 用java编写人机围棋游戏_JAVA写的围棋游戏的源代码.doc
  7. mstsc解决远程桌面连接提示远程终端连接数超过了允许连接数
  8. 小视频app源码,Android 滑动拼图验证码控件
  9. 第一百零六期:长相不讨AI喜欢面试就会挂?全球百万求职者经历AI“看脸”面试
  10. PM01-项目立项阶段-02-范围说明书