欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义View之自定义评价打分控件RatingBar实现自定义星星大小和间距

程序员文章站 2024-03-04 16:23:29
在android开发中,我们经常会用到对商家或者商品的评价,运用星星进行打分。然而在android系统中自带的打分控件,ratingbar特别不好用,间距和大小无法改变。所...

在android开发中,我们经常会用到对商家或者商品的评价,运用星星进行打分。然而在android系统中自带的打分控件,ratingbar特别不好用,间距和大小无法改变。所以,我就自定义了一个特别好用的打分控件。在项目中可以直接使用,特别简单。下面直接上图:

效果图

Android自定义View之自定义评价打分控件RatingBar实现自定义星星大小和间距

实现原理

其实就是自定义view继承linearlayout ,然后里面动态加了五个imageview。

实现代码,有详细的注释

在attrs中声明的可以在xml中设置的变量

<declare-styleable name="ratingbar">
<!--尺寸值-->
<attr name="starimagesize" format="dimension" />
<!--星星间距-->
<attr name="starpadding" format="dimension" />
<!--星星总数-->
<attr name="starcount" format="integer" />
<!--空白的星星资源文件值-->
<attr name="starempty" format="reference" />
<!--满星资源文件值-->
<attr name="starfill" format="reference" />
<!--半星资源文件值-->
<attr name="starhalf" format="reference" />
<!--是否可点击boolean值-->
<attr name="clickable" format="boolean" />
<!--当前进度float值-->
<attr name="starstep" format="float" />
<!--每次进度方式的值,整星还是半星-->
<attr name="stepsize">
<enum name="half" value="0" />
<enum name="full" value="1" />
</attr>
</declare-styleable>

ratingbar源码

import android.content.context;
import android.content.res.typedarray;
import android.graphics.drawable.drawable;
import android.util.attributeset;
import android.view.view;
import android.widget.imageview;
import android.widget.linearlayout;
import com.kejiang.yuandl.r;
import java.math.bigdecimal;
/**
* created by dylan on 2015/6/11.
* 自定义打分控件ratingbar
* 可以自定义星星大小和间距
* correction clickevent from xml
*/
public class ratingbar extends linearlayout {
/**
* 是否可点击
*/
private boolean mclickable;
/**
* 星星总数
*/
private int starcount;
/**
* 星星的点击事件
*/
private onratingchangelistener onratingchangelistener;
/**
* 每个星星的大小
*/
private float starimagesize;
/**
* 每个星星的间距
*/
private float starpadding;
/**
* 星星的显示数量,支持小数点
*/
private float starstep;
/**
* 空白的默认星星图片
*/
private drawable staremptydrawable;
/**
* 选中后的星星填充图片
*/
private drawable starfilldrawable;
/**
* 半颗星的图片
*/
private drawable starhalfdrawable;
/**
* 每次点击星星所增加的量是整个还是半个
*/
private stepsize stepsize;
/**
* 设置半星的图片资源文件
*
* @param starhalfdrawable
*/
public void setstarhalfdrawable(drawable starhalfdrawable) {
this.starhalfdrawable = starhalfdrawable;
}
/**
* 设置满星的图片资源文件
*
* @param starfilldrawable
*/
public void setstarfilldrawable(drawable starfilldrawable) {
this.starfilldrawable = starfilldrawable;
}
/**
* 设置空白和默认的图片资源文件
*
* @param staremptydrawable
*/
public void setstaremptydrawable(drawable staremptydrawable) {
this.staremptydrawable = staremptydrawable;
}
/**
* 设置星星是否可以点击操作
*
* @param clickable
*/
public void setclickable(boolean clickable) {
this.mclickable = clickable;
}
/**
* 设置星星点击事件
*
* @param onratingchangelistener
*/
public void setonratingchangelistener(onratingchangelistener onratingchangelistener) {
this.onratingchangelistener = onratingchangelistener;
}
/**
* 设置星星的大小
*
* @param starimagesize
*/
public void setstarimagesize(float starimagesize) {
this.starimagesize = starimagesize;
}
public void setstepsize(stepsize stepsize) {
this.stepsize = stepsize;
}
/**
* 构造函数
* 获取xml中设置的资源文件
*
* @param context
* @param attrs
*/
public ratingbar(context context, attributeset attrs) {
super(context, attrs);
setorientation(linearlayout.horizontal);
typedarray mtypedarray = context.obtainstyledattributes(attrs, r.styleable.ratingbar);
starimagesize = mtypedarray.getdimension(r.styleable.ratingbar_starimagesize, 20);
starpadding = mtypedarray.getdimension(r.styleable.ratingbar_starpadding, 10);
starstep = mtypedarray.getfloat(r.styleable.ratingbar_starstep, 1.0f);
stepsize = stepsize.fromstep(mtypedarray.getint(r.styleable.ratingbar_stepsize, 1));
starcount = mtypedarray.getinteger(r.styleable.ratingbar_starcount, 5);
staremptydrawable = mtypedarray.getdrawable(r.styleable.ratingbar_starempty);
starfilldrawable = mtypedarray.getdrawable(r.styleable.ratingbar_starfill);
starhalfdrawable = mtypedarray.getdrawable(r.styleable.ratingbar_starhalf);
mclickable = mtypedarray.getboolean(r.styleable.ratingbar_clickable, true);
mtypedarray.recycle();
for (int i = 0; i < starcount; ++i) {
final imageview imageview = getstarimageview();
imageview.setimagedrawable(staremptydrawable);
imageview.setonclicklistener(
new onclicklistener() {
@override
public void onclick(view v) {
if (mclickable) {
//浮点数的整数部分
int fint = (int) starstep;
bigdecimal b1 = new bigdecimal(float.tostring(starstep));
bigdecimal b2 = new bigdecimal(integer.tostring(fint));
//浮点数的小数部分
float fpoint = b1.subtract(b2).floatvalue();
if (fpoint == 0) {
fint -= 1;
}
if (indexofchild(v) > fint) {
setstar(indexofchild(v) + 1);
} else if (indexofchild(v) == fint) {
if (stepsize == stepsize.full) {//如果是满星 就不考虑半颗星了
return;
}
//点击之后默认每次先增加一颗星,再次点击变为半颗星
if (imageview.getdrawable().getcurrent().getconstantstate().equals(starhalfdrawable.getconstantstate())) {
setstar(indexofchild(v) + 1);
} else {
setstar(indexofchild(v) + 0.5f);
}
} else {
setstar(indexofchild(v) + 1f);
}
}
}
}
);
addview(imageview);
}
setstar(starstep);
}
/**
* 设置每颗星星的参数
*
* @return
*/
private imageview getstarimageview() {
imageview imageview = new imageview(getcontext());
linearlayout.layoutparams layout = new linearlayout.layoutparams(
math.round(starimagesize), math.round(starimagesize));//设置每颗星星在线性布局的大小
layout.setmargins(0, 0, math.round(starpadding), 0);//设置每颗星星在线性布局的间距
imageview.setlayoutparams(layout);
imageview.setadjustviewbounds(true);
imageview.setscaletype(imageview.scaletype.center_crop);
imageview.setimagedrawable(staremptydrawable);
imageview.setminimumwidth(10);
imageview.setmaxheight(10);
return imageview;
}
/**
* 设置星星的个数
*
* @param rating
*/
public void setstar(float rating) {
if (onratingchangelistener != null) {
onratingchangelistener.onratingchange(rating);
}
this.starstep = rating;
//浮点数的整数部分
int fint = (int) rating;
bigdecimal b1 = new bigdecimal(float.tostring(rating));
bigdecimal b2 = new bigdecimal(integer.tostring(fint));
//浮点数的小数部分
float fpoint = b1.subtract(b2).floatvalue();
//设置选中的星星
for (int i = 0; i < fint; ++i) {
((imageview) getchildat(i)).setimagedrawable(starfilldrawable);
}
//设置没有选中的星星
for (int i = fint; i < starcount; i++) {
((imageview) getchildat(i)).setimagedrawable(staremptydrawable);
}
//小数点默认增加半颗星
if (fpoint > 0) {
((imageview) getchildat(fint)).setimagedrawable(starhalfdrawable);
}
}
/**
* 操作星星的点击事件
*/
public interface onratingchangelistener {
/**
* 选中的星星的个数
*
* @param ratingcount
*/
void onratingchange(float ratingcount);
}
/**
* 星星每次增加的方式整星还是半星,枚举类型
* 类似于view.gone
*/
public enum stepsize {
half(0), full(1);
int step;
stepsize(int step) {
this.step = step;
}
public static stepsize fromstep(int step) {
for (stepsize f : values()) {
if (f.step == step) {
return f;
}
}
throw new illegalargumentexception();
}
}
}

在xml中的用法

<com.kejiang.yuandl.view.ratingbar
android:id="@+id/rb"
android:layout_width="360dp"
android:layout_height="50dp"
app:starcount="5"
app:starempty="@mipmap/star_grey"
app:starfill="@mipmap/star_yellow"
app:starhalf="@mipmap/star_half_yellow"
app:starimagesize="40dp"
app:starpadding="20dp"
app:starstep="1.5"
app:stepsize="half"></com.kejiang.yuandl.view.ratingbar>

在activity中的设置

ratingbar ratingbar= (ratingbar) findviewbyid(r.id.rb);
ratingbar.setclickable(true);//设置可否点击
ratingbar.setstar(2.5f);//设置显示的星星个数
ratingbar.setstepsize(ratingbar.stepsize.half);//设置每次点击增加一颗星还是半颗星
ratingbar.setonratingchangelistener(new ratingbar.onratingchangelistener() {
@override
public void onratingchange(float ratingcount) {//点击星星变化后选中的个数
log.d("ratingbar","ratingbar-count="+ratingcount);
}
});