public class CarSpeedDashboardView extends View {
private Paint mPaintOutDashboard;
private Paint mPaintSpeedPoint;
private Paint mPaintSpeedScale;
private Paint mPaintSpeedScaleText;
private Paint mPaintSpeedText;
private int outDashBoardWidth = 40;
private float rotateValue = 50;
private float DEFAULT_START_ANGLE = 50;
public CarSpeedDashboardView(Context context) {
this(context, null);
}
public CarSpeedDashboardView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CarSpeedDashboardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaintOutDashboard = new Paint();
mPaintOutDashboard.setStrokeWidth(outDashBoardWidth);
mPaintOutDashboard.setStyle(Paint.Style.STROKE);
mPaintOutDashboard.setTextAlign(Paint.Align.CENTER);
mPaintOutDashboard.setAntiAlias(true);
mPaintOutDashboard.setStrokeCap(Paint.Cap.ROUND);
mPaintSpeedPoint = new Paint();
mPaintSpeedPoint.setColor(Color.BLACK);
mPaintSpeedPoint.setStrokeWidth(20);
mPaintSpeedPoint.setAntiAlias(true);
mPaintSpeedPoint.setStyle(Paint.Style.STROKE);
mPaintSpeedPoint.setTextAlign(Paint.Align.CENTER);
mPaintSpeedPoint.setStrokeCap(Paint.Cap.ROUND);
mPaintSpeedScale = new Paint();
mPaintSpeedScale.setColor(Color.BLUE);
mPaintSpeedScale.setStrokeWidth(5);
mPaintSpeedScale.setAntiAlias(true);
mPaintSpeedScale.setStyle(Paint.Style.STROKE);
mPaintSpeedScaleText = new Paint();
mPaintSpeedScaleText.setColor(Color.BLACK);
mPaintSpeedScaleText.setStrokeWidth(3);
mPaintSpeedScaleText.setTextSize(26);
;
mPaintSpeedScaleText.setAntiAlias(true);
mPaintSpeedText = new Paint();
mPaintSpeedText.setColor(Color.BLACK);
mPaintSpeedText.setTextSize(48);
;
mPaintSpeedText.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
mPaintSpeedText.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = measureSpec(widthMeasureSpec);
int height = measureSpec(heightMeasureSpec);
setMeasuredDimension(Math.min(width,height), Math.min(width,height));
LinearGradient sweepGradient = new LinearGradient(0
, getMeasuredHeight(), getMeasuredWidth()
, getMeasuredHeight()
, Color.BLUE, Color.RED, Shader.TileMode.CLAMP);
mPaintOutDashboard.setShader(sweepGradient);
}
private int measureSpec(int measureSpec) {
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
int defaultWidth = 400;
switch (specMode) {
case MeasureSpec.EXACTLY:
defaultWidth = specSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
defaultWidth = 400;
break;
}
return defaultWidth;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(outDashBoardWidth / 2, outDashBoardWidth / 2, Math.min(getMeasuredWidth(), getMeasuredHeight()) - outDashBoardWidth / 2, Math.min(getMeasuredWidth(), getMeasuredHeight()) - outDashBoardWidth / 2, 140, 260, false, mPaintOutDashboard);
drawSpeedScale(canvas);
canvas.drawArc(outDashBoardWidth / 2, outDashBoardWidth / 2, Math.min(getMeasuredWidth(), getMeasuredHeight()) - outDashBoardWidth / 2, Math.min(getMeasuredWidth(), getMeasuredHeight()) - outDashBoardWidth / 2, 140, rotateValue - DEFAULT_START_ANGLE, false, mPaintSpeedPoint);
drawSpeedPoint(canvas);
drawCenterSpeedSize(canvas);
}
private void drawSpeedScale(Canvas canvas) {
canvas.save();
float sweepAngle = 260;
float a = sweepAngle / 26;
canvas.translate(Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2);
canvas.rotate(DEFAULT_START_ANGLE);
for (int i = 0; i <= 26; i++) {
if (i == 0 || i == 26 || i % 5 == 0) {
canvas.drawLine(0, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - outDashBoardWidth, 0, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - 80, mPaintSpeedScale);
} else {
canvas.drawLine(0, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - outDashBoardWidth, 0, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - 60, mPaintSpeedScale);
}
String text = i * 10 + "";
Rect rect = new Rect();
String msg = "999";
mPaintSpeedScaleText.getTextBounds(msg, 0, msg.length(), rect);
canvas.rotate(-90);
canvas.translate(-1 * (Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - outDashBoardWidth - 60-rect.width()/2), 0);
canvas.rotate(90 - DEFAULT_START_ANGLE - a * i);
canvas.drawText(text, 0, text.length(), 0, 0, mPaintSpeedScaleText);
canvas.rotate(-1 * (90 - DEFAULT_START_ANGLE - a * i));
canvas.translate(Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - outDashBoardWidth - 60-rect.width()/2, 0);
canvas.rotate(90);
canvas.rotate(a);
}
canvas.restore();
}
private void drawSpeedPoint(Canvas canvas) {
canvas.drawPoint(Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2, mPaintSpeedPoint);
canvas.save();
canvas.translate(Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2);
canvas.rotate(rotateValue);
canvas.drawLine(0, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - outDashBoardWidth * 4, 0, 0, mPaintSpeedPoint);
canvas.restore();
}
private void drawCenterSpeedSize(Canvas canvas) {
String value = Math.round(rotateValue - 50) + "";
Rect rect = new Rect();
mPaintSpeedText.getTextBounds(value, 0, value.length(), rect);
canvas.drawText(value, 0, value.length(), Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - rect.width() / 2
, Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2 - 40, mPaintSpeedText);
}
public void startAnimation() {
if (rotateValue != 50) {
return;
}
ValueAnimator valueAnimator = ValueAnimator.ofFloat(50, 310);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
rotateValue = (float) animation.getAnimatedValue();
if (rotateValue == 310) {
releaseAnimation();
}
invalidate();
}
});
valueAnimator.start();
}
public void releaseAnimation() {
if (rotateValue == 50) {
return;
}
ValueAnimator valueAnimator = ValueAnimator.ofFloat(50, 310);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
rotateValue = 360 - (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}
}