java 雷达图_Android雷达图(蜘蛛网图),自定义view之雷达图,正五边雷达图,分数图...

本文介绍了如何在Android中自定义实现雷达图(蜘蛛网图),包括绘制蜘蛛网、直线、标题和覆盖区域,适用于分数展示。代码示例详细解释了绘制过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近业务要做分数雷达图,到网上找了很大,原理都差不多,但是要适用自己的业务,还需要微调。下面是我微调后的效果图

6359adfc032a

雷达图蜘蛛网.png

原理很简单

1,确定雷达图中心点的坐标

2,用正三角sin,反三角函数cos计算五个类别的坐标点

3,绘制蜘蛛网

4,绘制直线

5,绘制覆盖区域(包含红点)

下面结合代码给大家讲解下

-1, 下面是需要用到的一些属性

public class RadarView extends View {

//数据个数

private int count = 5;

//成绩圆点半径

private int valueRadius = 8;

//网格最大半径

private float radius;

//中心X

private float centerX;

//中心Y

private float centerY;

//雷达区画笔

private Paint mainPaint;

//文本画笔

private Paint textPaint;

//数据区画笔

private Paint valuePaint;

//标题文字

private List titles;

//各维度分值

private List data;

//数据最大值

private double maxValue = 100;

//弧度

private float angle;

}

2,获取中心点坐标

这个是在view的onSizeChanged方法里获取当前view的宽高,取宽高的小值,然后再找中心点作为雷达图的中心点。这样做的好处是可以使雷达图自适应

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

radius = Math.min(w, h) / 2 * 0.8f;

centerX = w / 2;

centerY = h / 2;

//一旦size发生改变,重新绘制

postInvalidate();

super.onSizeChanged(w, h, oldw, oldh);

}

3,开始绘制

@Override

protected void onDraw(Canvas canvas) {

drawPolygon(canvas);//绘制蜘蛛网

drawLines(canvas);//绘制直线

drawTitle(canvas);//绘制标题

drawRegion(canvas);//绘制覆盖区域

}

下面贴出所有代码,代码里有很详细的注释

package com.example.qcl.demo.radarmap;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.support.annotation.Nullable;

import android.util.AttributeSet;

import android.view.View;

import java.util.ArrayList;

import java.util.List;

/**

* 2018/6/15 11:09

* Created by qcl

* wechat:2501902696

*/

public class RadarView extends View {

//数据个数

private int count = 5;

//成绩圆点半径

private int valueRadius = 8;

//网格最大半径

private float radius;

//中心X

private float centerX;

//中心Y

private float centerY;

//雷达区画笔

private Paint mainPaint;

//文本画笔

private Paint textPaint;

//数据区画笔

private Paint valuePaint;

//标题文字

private List titles;

//各维度分值

private List data;

//数据最大值

private double maxValue = 100;

//弧度

private float angle;

public RadarView(Context context) {

this(context, null);

}

public RadarView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public RadarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

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.BLACK);

textPaint.setTextAlign(Paint.Align.CENTER);

textPaint.setTextSize(30);

textPaint.setStrokeWidth(1);

textPaint.setAntiAlias(true);

//数据区(分数)画笔初始化

valuePaint = new Paint();

valuePaint.setColor(Color.RED);

valuePaint.setAntiAlias(true);

valuePaint.setStyle(Paint.Style.FILL);

titles = new ArrayList<>();

titles.add("语文");

titles.add("数学");

titles.add("英语");

titles.add("政治");

titles.add("历史");

count = titles.size();

//默认分数

data = new ArrayList<>(count);

data.add(100.0);

data.add(80.0);

data.add(90.0);

data.add(70.0);

data.add(60.0);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

radius = Math.min(w, h) / 2 * 0.8f;

centerX = w / 2;

centerY = h / 2;

//一旦size发生改变,重新绘制

postInvalidate();

super.onSizeChanged(w, h, oldw, oldh);

}

@Override

protected void onDraw(Canvas canvas) {

drawPolygon(canvas);//绘制蜘蛛网

drawLines(canvas);//绘制直线

drawTitle(canvas);//绘制标题

drawRegion(canvas);//绘制覆盖区域

}

/**

* 绘制多边形

*

* @param canvas

*/

private void drawPolygon(Canvas canvas) {

Path path = new Path();

//1度=1*PI/180 360度=2*PI 那么我们每旋转一次的角度为2*PI/内角个数

//中心与相邻两个内角相连的夹角角度

angle = (float) (2 * Math.PI / count);

//每个蛛丝之间的间距

float r = radius / (count - 1);

for (int i = 0; i < count; i++) {

//当前半径

float curR = r * i;

path.reset();

for (int j = 0; j < count; j++) {

if (j == 0) {

float x = (float) (centerX + curR * Math.sin(angle));

float y = (float) (centerY - curR * Math.cos(angle));

path.moveTo(x, y);

} else {

//根据半径,计算出蜘蛛丝上每个点的坐标

float x1 = (float) (centerX + curR * Math.sin(angle / 2));

float y1 = (float) (centerY + curR * Math.cos(angle / 2));

path.lineTo(x1, y1);

float x2 = (float) (centerX - curR * Math.sin(angle / 2));

float y2 = (float) (centerY + curR * Math.cos(angle / 2));

path.lineTo(x2, y2);

float x3 = (float) (centerX - curR * Math.sin(angle));

float y3 = (float) (centerY - curR * Math.cos(angle));

path.lineTo(x3, y3);

float x4 = centerX;

float y4 = centerY - curR;

path.lineTo(x4, y4);

float x = (float) (centerX + curR * Math.sin(angle));

float y = (float) (centerY - curR * Math.cos(angle));

path.lineTo(x, y);

}

}

path.close();

canvas.drawPath(path, mainPaint);

}

}

/**

* 绘制直线

*/

private void drawLines(Canvas canvas) {

Path path = new Path();

path.reset();

//直线1

path.moveTo(centerX, centerY);

float x1 = (float) (centerX + radius * Math.sin(angle));

float y1 = (float) (centerY - radius * Math.cos(angle));

path.lineTo(x1, y1);

//直线2

path.moveTo(centerX, centerY);

float x2 = (float) (centerX + radius * Math.sin(angle / 2));

float y2 = (float) (centerY + radius * Math.cos(angle / 2));

path.lineTo(x2, y2);

//直线3

path.moveTo(centerX, centerY);

float x3 = (float) (centerX - radius * Math.sin(angle / 2));

float y3 = (float) (centerY + radius * Math.cos(angle / 2));

path.lineTo(x3, y3);

//直线4

path.moveTo(centerX, centerY);

float x4 = (float) (centerX - radius * Math.sin(angle));

float y4 = (float) (centerY - radius * Math.cos(angle));

path.lineTo(x4, y4);

//直线5

path.moveTo(centerX, centerY);

float x5 = (float) (centerX);

float y5 = (float) (centerY - radius);

path.lineTo(x5, y5);

path.close();

canvas.drawPath(path, mainPaint);

}

/**

* 绘制标题文字

*

* @param canvas

*/

private void drawTitle(Canvas canvas) {

if (count != titles.size()) {

return;

}

Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();

float fontHeight = fontMetrics.descent - fontMetrics.ascent;//标题高度

//绘制文字1

float x1 = centerX;

float y1 = centerY - radius;

canvas.drawText(titles.get(0), x1, y1 - fontHeight / 5, textPaint);

//绘制文字2

float x2 = (float) (centerX + radius * Math.sin(angle));

float y2 = (float) (centerY - radius * Math.cos(angle));

float dis = textPaint.measureText(titles.get(1));//标题一半的宽度

canvas.drawText(titles.get(1), x2 + dis, y2 + fontHeight / 5, textPaint);

//绘制文字3

float x3 = (float) (centerX + radius * Math.sin(angle / 2));

float y3 = (float) (centerY + radius * Math.cos(angle / 2));

canvas.drawText(titles.get(2), x3, y3 + fontHeight, textPaint);

//绘制文字4

float x4 = (float) (centerX - radius * Math.sin(angle / 2));

float y4 = (float) (centerY + radius * Math.cos(angle / 2));

canvas.drawText(titles.get(3), x4, y4 + fontHeight, textPaint);

//绘制文字5

float x5 = (float) (centerX - radius * Math.sin(angle));

float y5 = (float) (centerY - radius * Math.cos(angle));

float dis5 = textPaint.measureText(titles.get(1));//标题的宽度

canvas.drawText(titles.get(4), x5 - dis5, y5 - fontHeight / 5, textPaint);

}

/**

* 绘制覆盖区域

*/

private void drawRegion(Canvas canvas) {

valuePaint.setAlpha(255);

Path path = new Path();

double dataValue;

double percent;

//绘制圆点1

dataValue = data.get(0);

if (dataValue != maxValue) {

percent = dataValue / maxValue;

} else {

percent = 1;

}

float x1 = centerX;

float y1 = (float) (centerY - radius * percent);

path.moveTo(x1, y1);

canvas.drawCircle(x1, y1, valueRadius, valuePaint);

//绘制圆点2

dataValue = data.get(1);

if (dataValue != maxValue) {

percent = dataValue / maxValue;

} else {

percent = 1;

}

float x2 = (float) (centerX + radius * percent * Math.sin(angle));

float y2 = (float) (centerY - radius * percent * Math.cos(angle));

path.lineTo(x2, y2);

canvas.drawCircle(x2, y2, valueRadius, valuePaint);

//绘制圆点3

dataValue = data.get(2);

if (dataValue != maxValue) {

percent = dataValue / maxValue;

} else {

percent = 1;

}

float x3 = (float) (centerX + radius * percent * Math.sin(angle / 2));

float y3 = (float) (centerY + radius * percent * Math.cos(angle / 2));

path.lineTo(x3, y3);

canvas.drawCircle(x3, y3, valueRadius, valuePaint);

//绘制圆点4

dataValue = data.get(3);

if (dataValue != maxValue) {

percent = dataValue / maxValue;

} else {

percent = 1;

}

float x4 = (float) (centerX - radius * percent * Math.sin(angle / 2));

float y4 = (float) (centerY + radius * percent * Math.cos(angle / 2));

path.lineTo(x4, y4);

canvas.drawCircle(x4, y4, valueRadius, valuePaint);

//绘制圆点5

dataValue = data.get(3);

if (dataValue != maxValue) {

percent = dataValue / maxValue;

} else {

percent = 1;

}

float x5 = (float) (centerX - radius * percent * Math.sin(angle));

float y5 = (float) (centerY - radius * percent * Math.cos(angle));

path.lineTo(x5, y5);

canvas.drawCircle(x5, y5, valueRadius, valuePaint);

path.close();

valuePaint.setStyle(Paint.Style.STROKE);

//绘制覆盖区域外的连线

canvas.drawPath(path, valuePaint);

//填充覆盖区域

valuePaint.setAlpha(128);

valuePaint.setStyle(Paint.Style.FILL);

canvas.drawPath(path, valuePaint);

}

//设置蜘蛛网颜色

public void setMainPaint(Paint mainPaint) {

this.mainPaint = mainPaint;

postInvalidate();

}

//设置标题颜色

public void setTextPaint(Paint textPaint) {

this.textPaint = textPaint;

}

//设置覆盖局域颜色

public void setValuePaint(Paint valuePaint) {

this.valuePaint = valuePaint;

postInvalidate();

}

//设置各门得分

public void setData(List data) {

this.data = data;

postInvalidate();

}

//设置满分分数,默认是100分满分

public void setMaxValue(float maxValue) {

this.maxValue = maxValue;

}

}

使用

1,在布局文件中

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@color/grey666"

android:orientation="vertical">

android:id="@+id/radarview"

android:layout_width="250dp"

android:layout_height="200dp"

android:background="@color/colorWhite"/>

android:layout_width="250dp"

android:layout_height="200dp"

android:layout_marginTop="30dp"

android:background="@color/colorWhite"/>

在activity中

public class RadarMapActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_radar_map);

RadarView radarview = findViewById(R.id.radarview);

List datas = new ArrayList<>();

datas.add(100.0);//语文100分

datas.add(80.0);//数学80分

datas.add(90.0);//英语90分

datas.add(70.0);//政治70分

datas.add(60.0);//历史60分

radarview.setData(datas);

}

}

显示样式

6359adfc032a

蜘蛛网.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值