android自定义雷达图
程序员文章站
2022-03-11 19:13:28
...
/**
* 雷达view
* 站不住
* 2018-06-21
*/
public class RadarView extends View{
private int centerX; //中心X
private int centerY; //中心Y
private float radius; //网格最大半径
private Paint mainPaint; //雷达区画笔
private Paint textPaint; //文本画笔
private Paint valuePaint; //数据区画笔
private int count = 6; //数据个数
private float angle = (float) (Math.PI*2/count);
private String[] titles = {"a","b","c","d","e","f"};
private double[] data = {100,60,60,60,100,50,10,20}; //各维度分值
private float maxValue = 100; //数据最大值
public RadarView(Context context) {
this(context,null);
}
public RadarView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* 初始化画笔
* */
private void init() {
mainPaint=new Paint();
mainPaint.setColor(Color.BLACK);
mainPaint.setAntiAlias(true);
mainPaint.setStrokeWidth(1);
mainPaint.setStyle(Paint.Style.STROKE);
textPaint=new Paint();
textPaint.setColor(Color.RED);
textPaint.setAntiAlias(true);
textPaint.setTextSize(32);
textPaint.setStyle(Paint.Style.STROKE);
valuePaint=new Paint();
// 覆盖区域,只要使用path记录下坐标点,然后设
valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
valuePaint.setColor(Color.BLUE);
valuePaint.setAntiAlias(true);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
centerX=w/2;
centerY=h/2;
radius = Math.min(h, w)/2*0.8f;
Log.d("===onSizeChanged======",Thread.currentThread().getName());
//一旦size发生改变,重新绘制(onDraw)
// postInvalidate(); //工作在子线程
invalidate(); // 工作在ui线程
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawPolygon(canvas);
drawLines(canvas);
drawText(canvas);
drawRegion(canvas);
}
/**
* 绘制正多边形
*/
private void drawPolygon(Canvas canvas) {
Path path = new Path();
float r = radius/(count-1);//r是蜘蛛丝之间的间距
for(int i=1;i<count;i++){//中心点不用绘制
float curR = r*i;//当前半径
path.reset();
for(int j=0;j<count;j++){
if(j==0){
//每一圈设置起点
path.moveTo(centerX+curR,centerY);
}else{
//根据半径,计算出蜘蛛丝上每个点的坐标
float x = (float) (centerX+curR*Math.cos(angle*j));
float y = (float) (centerY+curR*Math.sin(angle*j));
path.lineTo(x,y);
}
}
path.close();//闭合路径
canvas.drawPath(path, mainPaint);
}
}
/**
* 绘制直线
* 绘制从中心到末端的直线
* 同样根据半径,计算出每个末端坐标
*/
private void drawLines(Canvas canvas){
Path path = new Path();
for(int i=0;i<count;i++){
path.reset();
//设置每一次的起点为中心
path.moveTo(centerX, centerY);
float x = (float) (centerX+radius*Math.cos(angle*i));
float y = (float) (centerY+radius*Math.sin(angle*i));
//画线
path.lineTo(x, y);
canvas.drawPath(path, mainPaint);
}
}
/**
* 绘制文字
* @param canvas
* 对于文本的绘制,首先要找到末端的坐标,
* 由于末端和文本有一定距离,给每个末端加上这个距离以后,再绘制文本。
另外,当文本在左边时,由于不希望文本和蜘蛛网交叉,
我们可以先计算出文本的长度,然后使起始绘制坐标向左偏移这个长度。
*/
private void drawText(Canvas canvas){
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float fontHeight = fontMetrics.descent - fontMetrics.ascent;
for(int i=0;i<count;i++){
float x = (float) (centerX+(radius+fontHeight/2)*Math.cos(angle*i));
float y = (float) (centerY+(radius+fontHeight/2)*Math.sin(angle*i));
if(angle*i>=0&&angle*i<=Math.PI/2){//第4象限
canvas.drawText(titles[i], x,y,textPaint);
}else if(angle*i>=3*Math.PI/2&&angle*i<=Math.PI*2){//第3象限
canvas.drawText(titles[i], x,y,textPaint);
}else if(angle*i>Math.PI/2&&angle*i<=Math.PI){//第2象限
float dis = textPaint.measureText(titles[i]);//文本长度
canvas.drawText(titles[i], x-dis,y,textPaint);
}else if(angle*i>=Math.PI&&angle*i<3*Math.PI/2){//第1象限
float dis = textPaint.measureText(titles[i]);//文本长度
canvas.drawText(titles[i], x-dis,y,textPaint);
}
}
}
/**
* 绘制区域
* @param canvas
*使path包围区域被填充
*
*/
private void drawRegion(Canvas canvas){
Path path = new Path();
valuePaint.setAlpha(255);
for(int i=0;i<count;i++){
double percent = data[i]/maxValue;
float x = (float) (centerX+radius*Math.cos(angle*i)*percent);
float y = (float) (centerY+radius*Math.sin(angle*i)*percent);
if(i==0){
path.moveTo(x, centerY);
}else{
path.lineTo(x,y);
}
//绘制小圆点
canvas.drawCircle(x,y,10,valuePaint);
}
valuePaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, valuePaint);
valuePaint.setAlpha(127);
//绘制填充区域
valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawPath(path, valuePaint);
}
}
最终的实现效果就是这样的