Android自定义View之自定义评价打分控件RatingBar实现自定义星星大小和间距
程序员文章站
2024-03-04 16:23:29
在android开发中,我们经常会用到对商家或者商品的评价,运用星星进行打分。然而在android系统中自带的打分控件,ratingbar特别不好用,间距和大小无法改变。所...
在android开发中,我们经常会用到对商家或者商品的评价,运用星星进行打分。然而在android系统中自带的打分控件,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); } });