Java代碼
public class EvaluationView extends View {
private int mNormalColor;
private int mHighlightColor;
private int mLineCount;
private int mGeometryCount;
private float mNormalStrokeWidth;
private float mHighlightStrokeWidth;
private boolean mhighlightFill;
private boolean needUpWords;
private List<String> mTitles;
private List<Integer> levels;
private Paint mPaint;
private TextPaint mTextPaint;
private Path mPath;
private float mCenterX;
private float mCenterY;
private float mMaxRadius;
private float mAngle;
private int space;
public EvaluationView(Context context) {
this(context, null);
}
public EvaluationView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public EvaluationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.EvaluationView);
mNormalColor = array.getColor(R.styleable.EvaluationView_normalColor, Color.GRAY);
mHighlightColor = array.getColor(R.styleable.EvaluationView_highlightColor, Color.parseColor("#500000ff"));
int textColor = array.getColor(R.styleable.EvaluationView_android_textColor, Color.BLACK);
float textSize = array.getDimension(R.styleable.EvaluationView_android_textSize, AppUtils.sp2px(15, getResources().getDisplayMetrics()));
mLineCount = array.getInt(R.styleable.EvaluationView_lineCount, 5);
mGeometryCount = array.getInt(R.styleable.EvaluationView_geometryCount, 5);
mNormalStrokeWidth = array.getDimension(R.styleable.EvaluationView_normalStrokeWidth, AppUtils.dp2px(1, getResources().getDisplayMetrics()));
mHighlightStrokeWidth = array.getDimension(R.styleable.EvaluationView_highlightStrokeWidth, AppUtils.dp2px(5, getResources().getDisplayMetrics()));
mhighlightFill = array.getBoolean(R.styleable.EvaluationView_isHighlightFill, true);
needUpWords = array.getBoolean(R.styleable.EvaluationView_needUpwards, true);
array.recycle();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(textSize);
mTextPaint.setColor(textColor);
mPath = new Path();
mAngle = (float) (2 * Math.PI / mLineCount);
initTitles();
space = AppUtils.dp2px(4, getResources().getDisplayMetrics());
initLevels();
}
private void initTitles() {
mTitles = new ArrayList<>();
for (int i = 0; i < mLineCount; i++) {
mTitles.add("第" + i + "個");
}
}
private void initLevels() {
levels = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < mLineCount; i++) {
int e = random.nextInt(mGeometryCount + 1);
if (e == 0) {
e = 1;
}
levels.add(e);
}
}
public void setTitles(List<String> titles) {
if (titles != null && titles.size() > 0) {
mTitles = titles;
postInvalidate();
}
}
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(mCenterX, mCenterY);
if (needUpWords) {
canvas.save();
canvas.rotate(-90);
}
drawPloygon(canvas);
if (!needUpWords) {
drawText(canvas);
}
drawHighlight(canvas);
if (needUpWords) {
canvas.restore();
drawableUpWordsText(canvas);
}
}
/**
* 繪製多邊形
* 順時針繪製
*
* @param canvas
*/
private void drawPloygon(Canvas canvas) {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(mNormalColor);
mPaint.setStrokeWidth(mNormalStrokeWidth);
for (int i = 0; i < mGeometryCount; i++) {
float radius = mMaxRadius - i * mMaxRadius / mGeometryCount;
mPath.reset();
for (int j = 0; j < mLineCount; j++) {
float x = (float) (Math.cos(j * mAngle) * radius);
float y = (float) (Math.sin(j * mAngle) * radius);
if (j == 0) {
mPath.moveTo(x, y);
} else {
mPath.lineTo(x, y);
}
if (i == 0) {
canvas.drawLine(0, 0, x, y, mPaint);
}
}
mPath.close();
canvas.drawPath(mPath, mPaint);
}
}
/**
* 繪製文字,從x軸正方向開始繪製,順時針
*
* @param canvas
*/
private void drawText(Canvas canvas) {
Rect rect = new Rect();
for (int i = 0; i < mTitles.size(); i++) {
String title = mTitles.get(i);
mTextPaint.getTextBounds(title, 0, title.length(), rect);
float textWidth = rect.width();
float textHeight = rect.height();
float x = (float) (Math.cos(i * mAngle) * mMaxRadius);
float y = (float) (Math.sin(i * mAngle) * mMaxRadius);
if (x <= 0) {
x = x - textWidth - space;
} else {
x = x + space;
}
if (y > 0) {
y = y + textHeight;
} else {
y = y - space;
}
canvas.drawText(title, x, y, mTextPaint);
}
}
/**
* 繪製高亮部分
*
* @param canvas
*/
private void drawHighlight(Canvas canvas) {
if (mhighlightFill) {
mPaint.setStyle(Paint.Style.FILL);
} else {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mHighlightStrokeWidth);
}
mPaint.setColor(mHighlightColor);
mPath.reset();
for (int i = 0; i < levels.size(); i++) {
Integer level = levels.get(i);
float x = (float) (Math.cos(i * mAngle) * mMaxRadius * level / mGeometryCount);
float y = (float) (Math.sin(i * mAngle) * mMaxRadius * level / mGeometryCount);
if (i == 0) {
mPath.moveTo(x, y);
} else {
mPath.lineTo(x, y);
}
}
mPath.close();
canvas.drawPath(mPath, mPaint);
}
/**
* 繪製需要尖尖朝上的文字,因爲旋轉了-90度,所以從最上面開始繪製,順時針
*
* @param canvas
*/
private void drawableUpWordsText(Canvas canvas) {
int size = mTitles.size();
String title;
Rect rect = new Rect();
float textWidth;
float textHeight;
for (int i = 0; i < size; i++) {
title = mTitles.get(i);
mTextPaint.getTextBounds(title, 0, title.length(), rect);
textWidth = rect.width();
textHeight = rect.height();
if (i == 0) {
canvas.drawText(title, 0 - textWidth / 2, 0 - mMaxRadius - space, mTextPaint);
} else {
float x = (float) (mMaxRadius * Math.sin(i * mAngle));
float y = (float) (-mMaxRadius * Math.cos(i * mAngle));
if ((int) (Math.abs(x)) <= mMaxRadius * Math.sin(mAngle / 2)) {
x = x - textWidth / 2;
} else {
if (x <= 0) {
x = x - textWidth - space;
} else {
x = x + space;
}
}
y = y + textHeight / 2;
if (y >= mMaxRadius * Math.cos(mAngle / 2)) {
y += textHeight / 2 + space;
}
canvas.drawText(title, x, y, mTextPaint);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
width = AppUtils.dp2px(500, getResources().getDisplayMetrics());
}
if (heightMode != MeasureSpec.EXACTLY) {
height = AppUtils.dp2px(200, getResources().getDisplayMetrics());
}
setMeasuredDimension(width, height);
mCenterX = width / 2;
mCenterY = height / 2;
mMaxRadius = (Math.min(width, height) - AppUtils.dp2px(50, getResources().getDisplayMetrics())) / 2;
}
}
Style屬性
<declare-styleable name="EvaluationView">
<attr name="normalColor" format="color" />
<attr name="highlightColor" format="color" />
<attr name="isHighlightFill" format="boolean" />
<attr name="android:textColor" />
<attr name="android:textSize" />
<attr name="lineCount" format="integer" />
<attr name="geometryCount" format="integer" />
<attr name="normalStrokeWidth" format="dimension" />
<attr name="highlightStrokeWidth" format="dimension" />
<attr name="needUpwards" format="boolean" />
</declare-styleable>
使用
<com.star.testapplication.views.EvaluationView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="20dp"
android:visibility="visible"
app:geometryCount="4"
app:highlightStrokeWidth="2dp"
app:isHighlightFill="true"
app:lineCount="6"
app:needUpwards="false" />
效果
![這裏寫圖片描述]()