版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33666539/article/details/82421093
Java代码
public class EvaluationView extends View {
private int mNormalColor; //默认颜色
private int mHighlightColor; //高亮颜色
private int mLineCount; //n边型
private int mGeometryCount; //n边型的个数
private float mNormalStrokeWidth; //默认线的宽度
private float mHighlightStrokeWidth; //高亮线的宽度
private boolean mhighlightFill; //高亮部分是否是填充模式
private boolean needUpWords; //默认是从x轴正方向开始画,但是这样画出来的结果不一样尖尖朝上,这个属性就表示是否需要尖尖朝上,如果需要尖尖朝上那么会旋转-90度
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) { //如果尖尖需要朝上,则需要旋转-90度
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++) { //绘制n个多边形 从外往里面画
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) {
//如果宽度不是确切的值,那么给一个默认值500dp
width = AppUtils.dp2px(500, getResources().getDisplayMetrics());
}
if (heightMode != MeasureSpec.EXACTLY) {
//如果高度不是确切的值,给一个默认值200dp
height = AppUtils.dp2px(200, getResources().getDisplayMetrics());
}
setMeasuredDimension(width, height);
mCenterX = width / 2;
mCenterY = height / 2;
//最外层多边形的半径是取宽高的最小值 - 50dp后再除以2 ,为什么-50dp原因在于要预留出文字的区域,但50dp也可能不够,所以宽高要设好
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" />