先上效果图:
QQ20181226-180025-HD.gif
然后直接上代码:
public class InstrumentView extends View {
private Paint mPaint;
private Paint mPaint2;
private Paint mPaint3;
private Paint mPaint4;
private Paint mPaint5;
private Paint mPaint6;
private ValueAnimator mValueAnimator;
private int mValue;
public InstrumentView(Context context) {
super(context);
init();
}
public InstrumentView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public InstrumentView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
//五段圆弧的画笔
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(40);
mPaint.setColor(Color.parseColor("#cb393b"));
mPaint.setStrokeCap(Paint.Cap.ROUND);
//白色圆弧的画笔
mPaint2 = new Paint();
mPaint2.setStyle(Paint.Style.STROKE);
mPaint2.setAntiAlias(true);
mPaint2.setStrokeWidth(80);
mPaint2.setColor(Color.parseColor("#ffffff"));
mPaint2.setStrokeCap(Paint.Cap.ROUND);
//刻度虚线画笔
mPaint3 = new Paint();
mPaint3.setStyle(Paint.Style.STROKE);
mPaint3.setAntiAlias(true);
mPaint3.setStrokeWidth(5);
mPaint3.setColor(Color.parseColor("#b8b8b8"));
//指针线 画笔
mPaint4 = new Paint();
mPaint4.setStyle(Paint.Style.STROKE);
mPaint4.setAntiAlias(true);
mPaint4.setStrokeWidth(13);
mPaint4.setColor(Color.parseColor("#3dbddf"));
mPaint4.setStrokeCap(Paint.Cap.ROUND);
//最小值 画笔
mPaint5 = new Paint();
mPaint5.setStyle(Paint.Style.STROKE);
mPaint5.setAntiAlias(true);
mPaint5.setColor(Color.parseColor("#000000"));
mPaint5.setTextAlign(Paint.Align.CENTER);//设置文字对齐方式
mPaint5.setTextSize(140);
//最大值 画笔
mPaint6 = new Paint();
mPaint6.setStyle(Paint.Style.STROKE);
mPaint6.setAntiAlias(true);
mPaint6.setColor(Color.parseColor("#000000"));
mPaint6.setTextAlign(Paint.Align.LEFT);//设置文字对齐方式
mPaint6.setTextSize(30);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//这里为什么要收缩40:因为mPaint2.setStrokeWidth(80) 如果按照下面注释方法有一部分会绘制在画布外面
//RectF oval = new RectF(0, 0,getWidth(), getWidth());
RectF oval = new RectF(40, 40, getWidth() - 40, getWidth() - 40);
//白色背景
canvas.drawArc(oval, 0, -180, false, mPaint2);
//五段圆弧
mPaint.setColor(Color.parseColor("#cb393b"));
canvas.drawArc(oval, 0, -180 / 5, false, mPaint);
mPaint.setColor(Color.parseColor("#ff4a5b"));
canvas.drawArc(oval, -180 / 5, -180 / 5, false, mPaint);
mPaint.setColor(Color.parseColor("#ffdb82"));
canvas.drawArc(oval, -180 * 2 / 5, -180 / 5, false, mPaint);
mPaint.setColor(Color.parseColor("#75cd80"));
canvas.drawArc(oval, -180 * 3 / 5, -180 / 5, false, mPaint);
mPaint.setColor(Color.parseColor("#85dff6"));
canvas.drawArc(oval, -180 * 4 / 5, -180 / 5, false, mPaint);
//画刻度(总共31个刻度、第一个和最后一个长度增加颜色加深)
for (int i = 0; i <= 30; i++) {
int weight;
if (i == 30 || i == 0) {
mPaint3.setColor(Color.parseColor("#000000"));
weight = 30;
} else {
mPaint3.setColor(Color.parseColor("#b8b8b8"));
weight = 20;
}
//起始点80 + 20:80是白色圆弧的宽度、20是间隙
int startX = 80 + 20;
canvas.drawLine(startX, getWidth() / 2, startX + weight, getWidth() / 2, mPaint3);
canvas.save();
//逆时针旋转180 / 30度(最后一个刻度 不用旋转画布)
if (i != 30) {
canvas.rotate(180 / 30, getWidth() / 2, getWidth() / 2);
}
}
//把画布旋转回来
canvas.rotate(-180, getWidth() / 2, getWidth() / 2);
//画指针(一条线、一个箭头)
canvas.rotate((float) mValue / 10, getWidth() / 2, getWidth() / 2);
canvas.save();
//线
canvas.drawLine(10, getWidth() / 2, 70, getWidth() / 2, mPaint4);
//箭头
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.jiantou);
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
canvas.drawBitmap(bitmap, null, new Rect(100, getWidth() / 2 - bitmapHeight / 2,
100 + bitmapWidth, getWidth() / 2 + bitmapHeight / 2), null);
//把画布旋转回来
canvas.rotate(-(float) mValue / 10, getWidth() / 2, getWidth() / 2);
//画 文字(文字绘制到圆的中心位置)
Rect textRect = new Rect(0, 0, getWidth(), getWidth());
Paint.FontMetricsInt fontMetrics = mPaint5.getFontMetricsInt();
//获取基线
int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
canvas.drawText(mValue / 10 + "斤肉", textRect.centerX(), baseline, mPaint5);
//画最小值
mPaint6.setTextAlign(Paint.Align.LEFT);//左对齐方式
canvas.drawText("0", 150, getWidth() / 2 + 15, mPaint6);
//画最大值
mPaint6.setTextAlign(Paint.Align.RIGHT);//右对齐方式
canvas.drawText("180", getWidth() - 150, getWidth() / 2 + 15, mPaint6);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
// 在wrap_content的情况下默认长度为widthSpecSize * 3 / 5
int minSize = widthSpecSize * 3 / 5;
// wrap_content的specMode是AT_MOST模式,这种情况下宽/高等同于specSize
// 查表得这种情况下specSize等同于parentSize,也就是父容器当前剩余的大小
// 在wrap_content的情况下如果特殊处理,效果等同martch_parent
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(minSize, minSize);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(minSize, heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, minSize);
}
}
public void setValue(int weight) {
mValueAnimator = ValueAnimator.ofInt(0, weight * 10);
mValueAnimator.setDuration(3000);
mValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mValue = (int) valueAnimator.getAnimatedValue();
invalidate();
}
});
mValueAnimator.start();
}
}