自定义RatingBar,可设置图片大小、间隔,是否可触摸改变等级
先看下效果:当手指滑动(或点击)时,RatingBar的等级会跟着改变
QQ截图20190402143805.png第一步:自定义属性
<declare-styleable name="MyRatingBar">
<attr name="touchable" format="boolean" />
<attr name="level" format="integer" />
<attr name="item_size" format="dimension" />
<attr name="item_gap" format="dimension" />
<attr name="item_select_img" format="reference" />
<attr name="item_unselect_img" format="reference" />
</declare-styleable>
touchable :是否可触摸,改变level
level :等级
item_size :每个图片大小
item_gap :图片之间的间隔
item_select_img :选中时的图片
item_unselect_img :未选中时的图片
第二步:自定义View-MyRatingBar继承View,获取自定义属性
public MyRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyRatingBar);
touchable = ta.getBoolean(R.styleable.MyRatingBar_touchable, false);
itemSize = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_size, 60);
itemGap = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_gap, 0);
level = ta.getInt(R.styleable.MyRatingBar_level, 0);
selectImage = ta.getDrawable(R.styleable.MyRatingBar_item_select_img);
unselectImage = ta.getDrawable(R.styleable.MyRatingBar_item_unselect_img);
paint = new Paint();
}
第三步:重写onMeasure方法
当设置宽高大小为warp_content的时候,需要手动计算控件的大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = 0;
switch (widthMode) {
case MeasureSpec.AT_MOST:
width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
break;
case MeasureSpec.EXACTLY:
width = widthSize;
break;
case MeasureSpec.UNSPECIFIED:
width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
}
int height = 0;
switch (heightMode) {
case MeasureSpec.AT_MOST:
height = itemSize + getPaddingTop() + getPaddingBottom();
break;
case MeasureSpec.EXACTLY:
height = heightSize;
break;
case MeasureSpec.UNSPECIFIED:
height = itemSize + getPaddingTop() + getPaddingBottom();
break;
}
setMeasuredDimension(width, height);
}
第四步:重写onDraw方法
先整理下思路,
- 我打算用for循环画出5个星星,每画一个,就将画布向左移动一段距离(itemSize+itemGap),接着画下一个,直到画完。
- 画每一个时要判断这个应该画哪个图片
当touchable=false,比较简单,小于level的星星画成selectImage,大于level的为unselectImage.
当touchable=true,应该根据当前手指触摸的位置到左边的距离,判断当前位置应该画哪个图片,并设置等级level。
@Override
protected void onDraw(Canvas canvas) {
if (selectImage != null && unselectImage != null) {
int left = getPaddingLeft();
for (int i = 0; i < 5; i++) {
canvas.save();
canvas.translate(left, 0);
//是画选中状态的还是未选中状态的
Drawable drawable = null;
if (touchable && touchX != -1) {
if (touchX > getPaddingLeft() && touchX > left) {
if (touchX < left + itemSize + itemGap) {
level = i + 1;
}
drawable = selectImage;
} else {
drawable = unselectImage;
}
} else {
drawable = i < level ? selectImage : unselectImage;
}
int intrinsicWidth = drawable.getIntrinsicWidth();
int intrinsicHeight = drawable.getIntrinsicHeight();
//获取bitmap
Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
Canvas bitmapCanvas = new Canvas(bitmap);
drawable.setBounds(0, 0, intrinsicWidth, intrinsicHeight);
drawable.draw(bitmapCanvas);
//伸缩图片,并绘制
Matrix matrix = new Matrix();
matrix.postScale((float) itemSize / intrinsicWidth, (float) itemSize / intrinsicHeight);
canvas.drawBitmap(bitmap, matrix, paint);
left += (itemSize + itemGap);
canvas.restore();
}
}
}
第五步:重写onTouchEvent方法
获取触摸点的x坐标
@Override
public boolean onTouchEvent(MotionEvent event) {
touchX = (int) event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
invalidate();
break;
case MotionEvent.ACTION_MOVE:
invalidate();
break;
case MotionEvent.ACTION_UP:
invalidate();
break;
}
return true;
}
第六步:向外提供getter方法
public int getLevel() {
return level;
}
使用
在xml中:
<com.aomiao.ratingbar.MyRatingBar
android:id="@+id/ratingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:item_gap="10dp"
app:item_select_img="@mipmap/ic_rating_select"
app:item_size="30dp"
app:item_unselect_img="@mipmap/ic_rating"
app:level="3"
app:touchable="true" />
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="等级" />
Toast.makeText(MainActivity.this,
"等级" + ratingBar.getLevel(),
Toast.LENGTH_SHORT).show();
RatingBar完整代码
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MyRatingBar extends View {
private boolean touchable;
private int itemSize;
private int itemGap;
private int level;
private Drawable selectImage;
private Drawable unselectImage;
private Paint paint;
//触摸时的x坐标
private int touchX = -1;
public MyRatingBar(Context context) {
this(context, null);
}
public MyRatingBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyRatingBar);
touchable = ta.getBoolean(R.styleable.MyRatingBar_touchable, false);
itemSize = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_size, 60);
itemGap = ta.getDimensionPixelSize(R.styleable.MyRatingBar_item_gap, 0);
level = ta.getInt(R.styleable.MyRatingBar_level, 0);
selectImage = ta.getDrawable(R.styleable.MyRatingBar_item_select_img);
unselectImage = ta.getDrawable(R.styleable.MyRatingBar_item_unselect_img);
paint = new Paint();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width = 0;
switch (widthMode) {
case MeasureSpec.AT_MOST:
width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
break;
case MeasureSpec.EXACTLY:
width = widthSize;
break;
case MeasureSpec.UNSPECIFIED:
width = itemSize * 5 + itemGap * 4 + getPaddingLeft() + getPaddingRight();
}
int height = 0;
switch (heightMode) {
case MeasureSpec.AT_MOST:
height = itemSize + getPaddingTop() + getPaddingBottom();
break;
case MeasureSpec.EXACTLY:
height = heightSize;
break;
case MeasureSpec.UNSPECIFIED:
height = itemSize + getPaddingTop() + getPaddingBottom();
break;
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
if (selectImage != null && unselectImage != null) {
int left = getPaddingLeft();
for (int i = 0; i < 5; i++) {
canvas.save();
canvas.translate(left, 0);
//是画选中状态的还是未选中状态的
Drawable drawable = null;
if (touchable && touchX != -1) {
if (touchX > getPaddingLeft() && touchX > left) {
if (touchX < left + itemSize + itemGap) {
level = i + 1;
}
drawable = selectImage;
} else {
drawable = unselectImage;
}
} else {
drawable = i < level ? selectImage : unselectImage;
}
int intrinsicWidth = drawable.getIntrinsicWidth();
int intrinsicHeight = drawable.getIntrinsicHeight();
//获取bitmap
Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
Canvas bitmapCanvas = new Canvas(bitmap);
drawable.setBounds(0, 0, intrinsicWidth, intrinsicHeight);
drawable.draw(bitmapCanvas);
//伸缩图片,并绘制
Matrix matrix = new Matrix();
matrix.postScale((float) itemSize / intrinsicWidth, (float) itemSize / intrinsicHeight);
canvas.drawBitmap(bitmap, matrix, paint);
left += (itemSize + itemGap);
canvas.restore();
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
touchX = (int) event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
invalidate();
break;
case MotionEvent.ACTION_MOVE:
invalidate();
break;
case MotionEvent.ACTION_UP:
invalidate();
break;
}
return true;
}
public int getLevel() {
return level;
}
}
网友评论