package com.xw.sample.dashboardviewdemo;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* DashboardView style 3 仿最新版芝麻信用分
* Created by woxingxiao on 2016-11-28.
*/
public class DashboardView3 extends View {
private int mRadius; // 画布边缘半径(去除padding后的半径)
private int mStartAngle = 150; // 起始角度
private int mSweepAngle = 240; // 绘制角度
private int mMin = 350; // 最小值
private int mMax = 950; // 最大值
private String mHeaderText = "BETA"; // 表头
private int mCreditValue = 782; // 信用分
private int mSparkleWidth; // 亮点宽度
private int mProgressWidth; // 进度圆弧宽度
private float mLength1; // 刻度顶部相对边缘的长度
private float mLength2; // 信用值指示器顶部相对边缘的长度
private int mPadding;
private float mCenterX, mCenterY; // 圆心坐标
private Paint mPaint;
private RectF mRectFProgressArc;
private Rect mRectText;
private Path mPath;
private int[] mBgColors;
public DashboardView3(Context context) {
this(context, null);
}
public DashboardView3(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DashboardView3(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mSparkleWidth = dp2px(10);
mProgressWidth = 4;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setColor(Color.WHITE);
mRectFProgressArc = new RectF();
mRectText = new Rect();
mPath = new Path();
mBgColors = new int[]{ContextCompat.getColor(getContext(), R.color.color_red),
ContextCompat.getColor(getContext(), R.color.color_orange),
ContextCompat.getColor(getContext(), R.color.color_yellow),
ContextCompat.getColor(getContext(), R.color.color_green),
ContextCompat.getColor(getContext(), R.color.color_blue)};
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mPadding = Math.max(
Math.max(getPaddingLeft(), getPaddingTop()),
Math.max(getPaddingRight(), getPaddingBottom())
);
setPadding(mPadding, mPadding, mPadding, mPadding);
mLength1 = mPadding + mSparkleWidth / 2f + dp2px(8);
mLength2 = mLength1 + mProgressWidth + dp2px(4);
int width = resolveSize(dp2px(220), widthMeasureSpec);
mRadius = (width - mPadding * 2) / 2;
setMeasuredDimension(width, width - dp2px(50));
mCenterX = mCenterY = getMeasuredWidth() / 2f;
mRectFProgressArc.set(
mPadding + mSparkleWidth / 2f,
mPadding + mSparkleWidth / 2f,
getMeasuredWidth() - mPadding - mSparkleWidth / 2f,
getMeasuredWidth() - mPadding - mSparkleWidth / 2f
);
mPaint.setTextSize(sp2px(10));
mPaint.getTextBounds("0", 0, "0".length(), mRectText);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(calculateBGColorWithValue(mCreditValue));
/**
* 画进度圆弧背景
*/
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mProgressWidth);
mPaint.setAlpha(80);
canvas.drawArc(mRectFProgressArc, mStartAngle, mSweepAngle, false, mPaint);
mPaint.setAlpha(255);
/**
* 画进度圆弧(起始到信用值)
*/
mPaint.setShader(generateSweepGradient());
canvas.drawArc(mRectFProgressArc, mStartAngle,
calculateRelativeAngleWithValue(mCreditValue), false, mPaint);
/**
* 画信用值指示亮点
*/
float[] point = getCoordinatePoint(
mRadius - mSparkleWidth / 2f,
mStartAngle + calculateRelativeAngleWithValue(mCreditValue)
);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setShader(generateRadialGradient(point[0], point[1]));
canvas.drawCircle(point[0], point[1], mSparkleWidth / 2f, mPaint);
/**
* 画刻度
*/
int cnt = (mMax - mMin) / 2 / 10;
float degree = mSweepAngle / ((mMax - mMin) / 10);
float a = calculateRelativeAngleWithValue(mCreditValue);
float b = mSweepAngle / 2f;
mPaint.setShader(null);
mPaint.setAlpha(a >= b ? 200 : 80);
canvas.save();
canvas.drawLine(mCenterX, mPadding + mLength1, mCenterX, mPadding + mLength1 - 1, mPaint);
// 逆时针旋转
for (int i = 0; i < cnt; i++) {
canvas.rotate(-degree, mCenterX, mCenterY);
b -= degree;
mPaint.setAlpha(a >= b ? 200 : 80);
canvas.drawLine(mCenterX, mPadding + mLength1, mCenterX, mPadding + mLength1 - 1, mPaint);
}
canvas.restore();
canvas.save();
// 顺时针旋转
b = mSweepAngle / 2f;
for (int i = 0; i < cnt; i++) {
canvas.rotate(degree, mCenterX, mCenterY);
b += degree;
mPaint.setAlpha(a >= b ? 200 : 80);
canvas.drawLine(mCenterX, mPadding + mLength1, mCenterX, mPadding + mLength1 - 1, mPaint);
}
canvas.restore();
/**
* 画信用分指示器
*/
canvas.save();
b = mSweepAngle / 2f;
canvas.rotate(a - b, mCenterX, mCenterY);
mPaint.setAlpha(255);
mPaint.setStyle(Paint.Style.FILL);
mPath.reset();
mPath.moveTo(mCenterX, mPadding + mLength2);
mPath.rLineTo(-dp2px(2), dp2px(5));
mPath.rLineTo(dp2px(4), 0);
mPath.close();
canvas.drawPath(mPath, mPaint);
mPaint.setStrokeWidth(dp2px(1));
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(mCenterX, mPadding + mLength2 + dp2px(6) + 1, dp2px(2), mPaint);
canvas.restore();
/**
* 画实时度数值
*/
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(sp2px(35));
mPaint.setTextAlign(Paint.Align.CENTER);
String value = String.valueOf(mCreditValue);
canvas.drawText(value, mCenterX, mCenterY, mPaint);
/**
* 画信用描述
*/
mPaint.setTextSize(sp2px(14));
canvas.drawText(calculateCreditDescription(), mCenterX, mCenterY - dp2px(40), mPaint);
/**
* 画表头
*/
mPaint.setAlpha(160);
mPaint.setTextSize(sp2px(10));
canvas.drawText(mHeaderText, mCenterX, mCenterY - dp2px(65), mPaint);
/**
* 画评估时间
*/
mPaint.setAlpha(160);
mPaint.setTextSize(sp2px(9));
canvas.drawText(getFormatTimeStr(), mCenterX, mCenterY + dp2px(25), mPaint);
}
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
Resources.getSystem().getDisplayMetrics());
}
private int sp2px(int sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
Resources.getSystem().getDisplayMetrics());
}
private SweepGradient generateSweepGradient() {
SweepGradient sweepGradient = new SweepGradient(mCenterX, mCenterY,
new int[]{Color.argb(0, 255, 255, 255), Color.argb(200, 255, 255, 255)},
new float[]{0, calculateRelativeAngleWithValue(mCreditValue) / 360}
);
Matrix matrix = new Matrix();
matrix.setRotate(mStartAngle - 1, mCenterX, mCenterY);
sweepGradient.setLocalMatrix(matrix);
return sweepGradient;
}
private RadialGradient generateRadialGradient(float x, float y) {
return new RadialGradient(x, y, mSparkleWidth / 2f,
new int[]{Color.argb(255, 255, 255, 255), Color.argb(80, 255, 255, 255)},
new float[]{0.4f, 1},
Shader.TileMode.CLAMP
);
}
private float[] getCoordinatePoint(float radius, float angle) {
float[] point = new float[2];
double arcAngle = Math.toRadians(angle); //将角度转换为弧度
if (angle < 90) {
point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius);
point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius);
} else if (angle == 90) {
point[0] = mCenterX;
point[1] = mCenterY + radius;
} else if (angle > 90 && angle < 180) {
arcAngle = Math.PI * (180 - angle) / 180.0;
point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius);
point[1] = (float) (mCenterY + Math.sin(arcAngle) * radius);
} else if (angle == 180) {
point[0] = mCenterX - radius;
point[1] = mCenterY;
} else if (angle > 180 && angle < 270) {
arcAngle = Math.PI * (angle - 180) / 180.0;
point[0] = (float) (mCenterX - Math.cos(arcAngle) * radius);
point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius);
} else if (angle == 270) {
point[0] = mCenterX;
point[1] = mCenterY - radius;
} else {
arcAngle = Math.PI * (360 - angle) / 180.0;
point[0] = (float) (mCenterX + Math.cos(arcAngle) * radius);
point[1] = (float) (mCenterY - Math.sin(arcAngle) * radius);
}
return point;
}
/**
* 相对起始角度计算信用分所对应的角度大小
*/
private float calculateRelativeAngleWithValue(int value) {
return mSweepAngle * value * 1f / mMax;
}
/**
* 信用分对应信用描述
*/
private String calculateCreditDescription() {
if (mCreditValue > 700) {
return "信用极好";
} else if (mCreditValue > 650) {
return "信用优秀";
} else if (mCreditValue > 600) {
return "信用良好";
} else if (mCreditValue > 550) {
return "信用中等";
}
return "信用较差";
}
/**
* 信用分对应信用描述
*/
private int calculateBGColorWithValue(int value) {
if (value > 700) {
return mBgColors[4];
} else if (value > 650) {
return mBgColors[3];
} else if (value > 600) {
return mBgColors[2];
} else if (value > 550) {
return mBgColors[1];
}
return mBgColors[0];
}
private SimpleDateFormat mDateFormat;
private String getFormatTimeStr() {
if (mDateFormat == null) {
mDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
}
return String.format("评估时间:%s", mDateFormat.format(new Date()));
}
public int getCreditValue() {
return mCreditValue;
}
/**
* 设置信用值
*
* @param creditValue 信用值
*/
public void setCreditValue(int creditValue) {
if (mCreditValue == creditValue || creditValue < mMin || creditValue > mMax) {
return;
}
mCreditValue = creditValue;
postInvalidate();
}
}