先上效果圖:
然后直接上代碼:
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);//設(shè)置文字對(duì)齊方式
mPaint5.setTextSize(140);
//最大值 畫筆
mPaint6 = new Paint();
mPaint6.setStyle(Paint.Style.STROKE);
mPaint6.setAntiAlias(true);
mPaint6.setColor(Color.parseColor("#000000"));
mPaint6.setTextAlign(Paint.Align.LEFT);//設(shè)置文字對(duì)齊方式
mPaint6.setTextSize(30);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//這里為什么要收縮40:因?yàn)閙Paint2.setStrokeWidth(80) 如果按照下面注釋方法有一部分會(huì)繪制在畫布外面
//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個(gè)刻度睛竣、第一個(gè)和最后一個(gè)長(zhǎng)度增加顏色加深)
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;
}
//起始點(diǎn)80 + 20:80是白色圓弧的寬度窖维、20是間隙
int startX = 80 + 20;
canvas.drawLine(startX, getWidth() / 2, startX + weight, getWidth() / 2, mPaint3);
canvas.save();
//逆時(shí)針旋轉(zhuǎn)180 / 30度(最后一個(gè)刻度 不用旋轉(zhuǎn)畫布)
if (i != 30) {
canvas.rotate(180 / 30, getWidth() / 2, getWidth() / 2);
}
}
//把畫布旋轉(zhuǎn)回來
canvas.rotate(-180, getWidth() / 2, getWidth() / 2);
//畫指針(一條線近零、一個(gè)箭頭)
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);
//把畫布旋轉(zhuǎn)回來
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);//左對(duì)齊方式
canvas.drawText("0", 150, getWidth() / 2 + 15, mPaint6);
//畫最大值
mPaint6.setTextAlign(Paint.Align.RIGHT);//右對(duì)齊方式
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的情況下默認(rèn)長(zhǎng)度為widthSpecSize * 3 / 5
int minSize = widthSpecSize * 3 / 5;
// wrap_content的specMode是AT_MOST模式,這種情況下寬/高等同于specSize
// 查表得這種情況下specSize等同于parentSize镊屎,也就是父容器當(dāng)前剩余的大小
// 在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();
}
}