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

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

效果图

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

实现原理

其实就是自定义View继承LinearLayout ,然后里面动态加了五个ImageView。

实现代码,有详细的注释

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
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中的设置

1
2
3
4
5
6
7
8
9
10
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);
}
});

原文链接:http://blog.****.net/linglongxin24/article/details/52918701