万能自定义RatingBar 用起来简单易理解
今天在项目中写到一个类似美团、滴滴这种市面上常用的带星评价的需求,于是拿到需求的第一反应就是去找度娘了,然后了解到google有一种控件叫RatingBar,因为以前没有做过类似的需求,所以第一反应很开森。但是当拿到用的时候才发现啊并不是那么的如人意,因为这个扩展性太弱,基本上不能满足大众的自定义需求。 然后由于自己项目的需求,又找了一些其它的帖子看了下,感觉都不怎么适合,然后去看了RatingBar的源码之后决定自己动手自定义一个。先看效果图:
废话不多说 ,直接怼代码:
这是drawable文件 这里面主要是设置选中时候的star的样式以及没有选中时候的样式:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background"
android:drawable="@drawable/star_20x20_hl" />
<item android:id="@android:id/secondaryProgress"
android:drawable="@drawable/star_20x20_n" />
<item android:id="@android:id/progress"
android:drawable="@drawable/star_20x20_n" />
</layer-list>
接下来是自定义类里需要的attrs
<?xml version="1.0" encoding="utf-8"?>
<resources><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>
</resources>
然后直接贴出自定义类 继承LinearLayout
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.hconline.antapp_client.R; import java.math.BigDecimal; /** * Created by dylan on 2015/6/11. * 自定义打分控件RatingBar * 可以自定义星星大小和间距 * Correction clickEvent from Xml */ public class RatingBar extends LinearLayout { private int starNum; public float getStarNum() { return starNum; } public void setStarNum(int starNum) { this.starNum = starNum; } /** * 是否可点击 */ 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; } public RatingBar(Context context) { super(context); } /** * 构造函数 * 获取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); } setA(fint); //设置没有选中的星星 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.hconline.antapp_client.utils.RatingBar android:id="@+id/ratingbar2" android:layout_toRightOf="@+id/serve_attitude" android:layout_width="wrap_content" android:layout_height="wrap_content" app:starCount="5" app:starEmpty="@drawable/star_22x22_n" app:starFill="@drawable/star_22x22_hl" app:starImageSize="20dp" app:starPadding="10dp" app:starStep="0.0" android:layout_marginLeft="3dp" android:layout_centerHorizontal="true" />
属性解释:
app:starEmpty="@drawable/star_22x22_n" app:starFill="@drawable/star_22x22_hl"
这连个属性是设置你要得星的样式 我这边是正常的星星的样子 所以我就直接给的一张星星默没选中的样式和一张默认选中的样式,如果你的需求是显示其它样式 直接
上样式的bg图片就ok
eg:
app:starCount="5"
这个属性是设置星显示的数量
app:starImageSize="20dp"
这个是设置大小
app:starPadding="10dp" app:starStep="0.0"
这个是分别是这只星星之间的间距以及初始化的时候显示几颗被选中的星星
有的人到这儿会疑惑 ,效果是出来了,那怎么去获取或者是监听用户点击的星星呢,因为总台有一
个值去和后台交互的。这个肯定是有的
private int starNum; //记录用户点击的星星 public float getStarNum() { return starNum; } public void setStarNim(int starNum) { this.starNum= starNum; }
我想我贴两张图你们应该就明白了!
帖子写得不怎么好,还请大家多多支持!