新的需求很多地方RatingBar使用同一个素材,然而控件的大小却不一样。
系统的RatingBar图片不可缩放,还有坑,要设置minWidth等。
自己撸一个,先放效果图:
可拉伸星星控件代码:
public class ScalingRatingBar extends LinearLayout {
private static final int STAR_COUNT = 5;
private float rating;
private int fadeColor;
private Drawable drawable;
private float spacing;
public ScalingRatingBar(Context context) {
this(context, null);
}
public ScalingRatingBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ScalingRatingBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScalingRatingBar, defStyleAttr, 0);
drawable = typedArray.getDrawable(R.styleable.ScalingRatingBar_drawable);
rating = typedArray.getFloat(R.styleable.ScalingRatingBar_rating, 0.0f);
fadeColor = typedArray.getColor(R.styleable.ScalingRatingBar_fade_color, Color.GRAY);
spacing = typedArray.getDimension(R.styleable.ScalingRatingBar_spacing, 0);
typedArray.recycle();
init();
}
private void init() {
setOrientation(HORIZONTAL);
for (int i = 0; i < STAR_COUNT; ++i) {
StarImageView view = createStarView();
addView(view, -2, -2);
if (i < STAR_COUNT - 1) {
addView(new View(getContext()), (int) spacing, -1);
}
}
updateRating();
}
private void updateRating(){
int index = 0;
for (int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
if (v instanceof StarImageView) {
StarImageView view = (StarImageView) v;
float lhs = (index) * 1f;
float rhs = (index + 1) * 1f;
float subRatio;
if (rating < lhs) {
subRatio = 0;
} else if (rating > rhs) {
subRatio = 1;
} else {
subRatio = rating - (float) ((int) (rating));
}
view.setRating(subRatio);
index++;
}
}
}
private StarImageView createStarView() {
StarImageView view = new StarImageView(getContext());
view.setImageDrawable(drawable);
view.setFadeColor(fadeColor);
return view;
}
@Override
public void setLayoutParams(ViewGroup.LayoutParams params) {
super.setLayoutParams(params);
resetStarViewHeight();
}
public void setRating(float rating){
this.rating = rating;
updateRating();
}
private boolean heightReset = false;
private void resetStarViewHeight() {
if (heightReset) {
return;
}
heightReset = true;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
if (layoutParams != null) {
if (layoutParams.height > 0) {
for (int i = 0; i < getChildCount(); i++) {
View v = getChildAt(i);
if (v instanceof StarImageView) {
StarImageView starImageView = (StarImageView) v;
ViewGroup.LayoutParams lp = starImageView.getLayoutParams();
if (lp != null) {
lp.width = lp.height = layoutParams.height;
starImageView.setLayoutParams(lp);
}
}
}
}
}
}
private static class StarImageView extends AppCompatImageView {
private Bitmap bufferBitmap;
private Canvas bufferCanvas;
private Paint mixPaint, drawPaint;
private float rating;
private int fadeColor;
public StarImageView(Context context) {
super(context);
}
private void initDualBuffer() {
if (bufferBitmap == null) {
bufferBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
bufferCanvas = new Canvas(bufferBitmap);
mixPaint = new Paint();
mixPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
mixPaint.setColor(fadeColor);
drawPaint = new Paint();
}
}
@Override
protected void onDraw(Canvas canvas) {
initDualBuffer();
super.onDraw(bufferCanvas);
int left = (int) (rating * getMeasuredWidth());
bufferCanvas.drawRect(left, 0, getMeasuredWidth(), getMeasuredHeight(), mixPaint);
canvas.drawBitmap(bufferBitmap, 0, 0, drawPaint);
}
public void setRating(float rating) {
this.rating = rating;
invalidate();
}
public void setFadeColor(int fadeColor) {
this.fadeColor = fadeColor;
}
}
}
attrs.xml配置也贴出来:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ScalingRatingBar">
<attr name="drawable" format="reference"/>
<attr name="rating" format="float" />
<attr name="fade_color" format="color" />
<attr name="spacing" format="dimension" />
</declare-styleable>
</resources>
注意:控件的取值范围为0-5,如果范围不统一要先进行一次转换。
图片尺寸以控件高度为准,如果高度为WRAP_CONTENT或者MATCH_PATENT则使用图片原有尺寸
暂时使用fade_color填充缺失的星星,如果要输入两个drawable请自行修改。
控件的使用:
<com.ny.test.ScalingRatingBar
android:id="@+id/rb_rate"
android:layout_width="match_parent"
android:layout_height="30dp"
app:ratio="3.5"
app:fade_color="#d8d8d8"
app:spacing="44dp"
app:drawable="@drawable/icon_star_selected"/>