自定义蜘蛛网图RadarView
2019-12-04 本文已影响0人
小玉1991
工作中遇到上面的需求,查询资料后,自己做了优化,总结一下
要求还有相关的图层,图层还有边框。


先看在页面中的使用方法
radar_view.setNames(mDiagnosisBean.names);
radar_view.cleanRegions();
//图层1
radar_view.addRegion(R.color.color_99FFE27F, R.color.color_F8D353,
R.color.color_E9AD68, lsit1, 12);
//图层2
radar_view.addRegion(R.color.color_99B6E89C, R.color.color_39D075,
R.color.color_00BA7E, lsit2, 19);
radar_view.invalidate();
RadarView 直接上代码
public class RadarView extends View {
private int count = 3; //几边形
private int layerCount = 5; //层数
private double angle; //每条边对应的圆心角
private int centerX; //圆心x
private int centerY; //圆心y
private float radius; //半径
private Paint polygonPaint; //边框paint
// private Paint linePaint; //连线paint
private Paint txtPaint; //文字paint
private List<String> datas;
private List<Region> mRegions = new ArrayList<>();
public RadarView(Context context) {
this(context, null, 0);
}
public RadarView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public RadarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
datas = new ArrayList<>();
polygonPaint = new Paint();
polygonPaint.setColor(Color.parseColor("#C4C4C4"));
polygonPaint.setAntiAlias(true);
polygonPaint.setStyle(Paint.Style.STROKE);
polygonPaint.setStrokeWidth(1f);
// linePaint = new Paint();
// linePaint.setColor(ContextCompat.getColor(context, android.R.color.background_dark));
// linePaint.setAntiAlias(true);
// linePaint.setStyle(Paint.Style.STROKE);
// linePaint.setStrokeWidth(2f);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
radius = Math.min(h, w) / 2 * 0.85f;
centerX = w / 2;
centerY = h / 2;
}
public void setNames(List<String> list) {
setNames(list, R.color.local_test_Judge_background, 16);
}
public void setNames(List<String> list, int textColor, int size) {
this.datas.clear();
this.datas.addAll(list);
if (datas != null && datas.size() > 0) {
txtPaint = new Paint();
txtPaint.setColor(getResources().getColor(textColor));
txtPaint.setAntiAlias(true);
txtPaint.setStyle(Paint.Style.STROKE);
txtPaint.setTextSize(PixelUtil.dp2px(size));
}
}
public void cleanRegions() {
mRegions.clear();
}
public void addRegion(int colorInside, int colorBorder, int colorText, List<Float> list, int sizeText) {
Region region = new Region();
region.setColorIn(colorInside);
region.setColorBorder(colorBorder);
region.setList(list);
region.setSizeText(sizeText);
region.setColorText(colorText);
mRegions.add(region);
}
private void drawRegion(int colorInside, int colorBorder, int textColor, int textSize, List<Float> list, Canvas canvas) {
Paint paintIn = new Paint();
paintIn.setColor(getResources().getColor(colorInside));
paintIn.setStyle(Paint.Style.FILL);
paintIn.setAntiAlias(true);
Path path = new Path();
for (int i = 0; i < list.size(); i++) {
float curR = list.get(i); //当前位置所在的数值
curR = curR * radius;
if (i == 0) {
path.moveTo(centerX, centerY - curR);
} else {
float x = (float) (centerX + Math.sin(angle * i) * curR);
float y = (float) (centerY - Math.cos(angle * i) * curR);
path.lineTo(x, y);
}
}
path.close();
canvas.drawPath(path, paintIn);
drawBorder(colorBorder, textColor, textSize, list, canvas);
}
private int textPerOff = -3;
private void drawBorder(int colorBorder, int textColor, int textSize, List<Float> list, Canvas canvas) {
Paint paintBorder = new Paint();
paintBorder.setColor(getResources().getColor(colorBorder));
paintBorder.setStyle(Paint.Style.STROKE);
paintBorder.setAntiAlias(true);
Paint paint = new Paint();
paint.setColor(getResources().getColor(textColor));
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setTextSize(PixelUtil.dp2px(textSize));
Path path = new Path();
for (int j = 0; j < count; j++) {
float curR = list.get(j); //当前位置所在的数值
float height = curR * radius;
if (j == 0) {
//第一个点坐标
path.moveTo(centerX, centerY - height);
drawPercent(canvas, paint, ((int) curR * 100) + "%", centerX, centerY - height, textPerOff, j);
} else {
//顺时针记录其余顶角的点坐标
float x = (float) (centerX + Math.sin(angle * j) * height);
float y = (float) (centerY - Math.cos(angle * j) * height);
path.lineTo(x, y);
drawPercent(canvas, paint, ((int) curR * 100) + "%", x, y, textPerOff, j);
}
}
path.close();
canvas.drawPath(path, paintBorder);
}
private void drawPercent(Canvas canvas, Paint paint, String text, float x, float y, int off, int i) {
if (angle * i == 0) {
//第一个文字位于顶角正上方
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(text, x, y - dp2px(off), paint);
paint.setTextAlign(Paint.Align.LEFT);
} else if (angle * i > 0 && angle * i < Math.PI / 2) {
//微调
canvas.drawText(text, x + dp2px(off), y + dp2px(off), paint);
} else if (angle * i >= Math.PI / 2 && angle * i < Math.PI) {
//最右下的文字获取到文字的长、宽,按文字长度百分比向左移
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
float height = bounds.bottom - bounds.top;
float width = paint.measureText(text);
canvas.drawText(text, x - width * 0.2f, y + height + dp2px(off), paint);
} else if (angle * i >= Math.PI && angle * i < 3 * Math.PI / 2) {
//同理最左下的文字获取到文字的长、宽,按文字长度百分比向左移
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
float width = paint.measureText(text);
float height = bounds.bottom - bounds.top;
canvas.drawText(text, x - width * 0.8f, y + height + dp2px(off), paint);
} else if (angle * i >= 3 * Math.PI / 2 && angle * i < 2 * Math.PI) {
//文字向左移动
String txt = text;
float width = paint.measureText(txt);
canvas.drawText(txt, x - width - dp2px(off), y + dp2px(off), paint);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (datas != null && datas.size() > 0) {
count = datas.size();
//计算圆心角
angle = Math.PI * 2 / count;
drawPolygon(canvas);//画边
drawText(canvas);//描绘文字
// drawLines(mCanvas);//画线
//drawRegion(canvas);//覆盖区域
if (mRegions != null && mRegions.size() > 0) {
for (Region region : mRegions) {
drawRegion(region.getColorIn(), region.getColorBorder(),
region.getColorText(), region.getSizeText(),
region.getList(), canvas);
}
}
}
}
private void drawPolygon(Canvas canvas) {
Path path = new Path();
float r = radius / layerCount;
for (int i = 1; i <= layerCount; i++) {
float curR = r * i; //当前所在层的半径
for (int j = 0; j < count; j++) {
if (j == 0) {
//每一层第一个点坐标
path.moveTo(centerX, centerY - curR);
} else {
//顺时针记录其余顶角的点坐标
float x = (float) (centerX + Math.sin(angle * j) * curR);
float y = (float) (centerY - Math.cos(angle * j) * curR);
path.lineTo(x, y);
}
}
path.close();
canvas.drawPath(path, polygonPaint);
}
}
/*private void drawLines(Canvas canvas) {
float r = radius / layerCount;
for (int i = 0; i < count; i++) {
//起始坐标 从中心开始的话 startx=centerX , startY=centerY
float startX = (float) (centerX + Math.sin(angle * i) * r);
float startY = (float) (centerY - Math.cos(angle * i) * r);
//末端坐标
float endX = (float) (centerX + Math.sin(angle * i) * radius);
float endY = (float) (centerY - Math.cos(angle * i) * radius);
canvas.drawLine(startX, startY, endX, endY, linePaint);
}
}*/
private int mTextDistance = 5;
private void drawText(Canvas canvas) {
for (int i = 0; i < count; i++) {
txtPaint.setTextAlign(Paint.Align.CENTER);
String txt = datas.get(i);
Rect bounds = new Rect();
txtPaint.getTextBounds(txt, 0, txt.length(), bounds);
float height = bounds.bottom - bounds.top;
float width = txtPaint.measureText(txt);
mTextDistance= (int) height;
//获取到雷达图最外边的坐标
float x = (float) (centerX + Math.sin(angle * i) * (radius + dp2px(mTextDistance)));
float y = (float) (centerY - Math.cos(angle * i) * (radius + dp2px(mTextDistance)));
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawCircle(x, y,5, paint);
x = (float) (x + Math.sin(angle * i) * width/2);
// y = (float) (y - Math.cos(angle * i) * height/2);
y = y + height / 2;
canvas.drawText(txt, x, y, txtPaint);
}
}
// private void drawRegion(Canvas canvas) {
// Path path = new Path();
// float r = radius / layerCount;//每层的间距
// for (int i = 0; i < count; i++) {
// if (i == 0) {
// path.moveTo(centerX, (float) (centerY - r - (radius - r) * datas.get(i).getValue()));
// } else {
// float x = (float) (centerX + Math.sin(angle * i) * ( datas.get(i).getValue() * (radius - r) + r));
// float y = (float) (centerY - Math.cos(angle * i) * ( datas.get(i).getValue() * (radius - r) + r));
// path.lineTo(x, y);
// }
// }
// path.close();
// canvas.drawPath(path, regionColorPaint);
// }
private int dp2px(int dp) {
return PixelUtil.dp2px(dp);
}
//设置几边形,**注意:设置几边形需要重新计算圆心角**
public void setCount(int count) {
this.count = count;
angle = (float) (Math.PI * 2 / count);
invalidate();
}
//设置层数
public void setLayerCount(int layerCount) {
this.layerCount = layerCount;
invalidate();
}
public static class Region {
private int colorIn;
private int colorBorder;
private int colorText;
private int sizeText;
private List<Float> list;
public int getColorIn() {
return colorIn;
}
public void setColorIn(int colorIn) {
this.colorIn = colorIn;
}
public int getColorBorder() {
return colorBorder;
}
public void setColorBorder(int colorBorder) {
this.colorBorder = colorBorder;
}
public List<Float> getList() {
return list;
}
public void setList(List<Float> list) {
this.list = list;
}
public int getColorText() {
return colorText;
}
public void setColorText(int colorText) {
this.colorText = colorText;
}
public int getSizeText() {
return sizeText;
}
public void setSizeText(int sizeText) {
this.sizeText = sizeText;
}
}
}