package com.example.kotlintest;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class RadarChartView extends View {
private List<DimensionBean> dimensionList;
private Paint linePaint;
private Paint shadowPaint;
private Paint pointPaint;
//里面放放射线的path
private List<PathMeasure> pathMeasureList;
//放射线的path
private List<Path> pathList;
// 放放射线与环线交叉点的位置
private List<List<float[]>> intersectionList;
// 每个放射线配置一个matrix
private List<Matrix> matrixList;
// 有几个刻度
private int scale;
// 每个刻度都有环线
private List<Path> loopPathList;
// 放射线刻度最大值
private float maxValue;
// 链接放射线上的刻度的path
private Path valuePath;
// 链接放射线上的刻度的点
private List<float[]> valueList;
// 原点的半径
private int circleWidth;
// 确定绘制文字的地方
public RadarChartView(Context context) {
super(context);
initView();
}
public RadarChartView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
public RadarChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public RadarChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
}
private void initView() {
linePaint = new Paint();
linePaint.setColor(Color.BLACK);
linePaint.setStrokeWidth(UIUtils.dp2px(getContext(), 1));
linePaint.setAntiAlias(true);
linePaint.setStyle(Paint.Style.STROKE);
pointPaint = new Paint();
pointPaint.setAntiAlias(true);
pointPaint.setColor(Color.parseColor("#3bFB725B"));
shadowPaint = new Paint();
shadowPaint.setStyle(Paint.Style.FILL);
shadowPaint.setAntiAlias(true);
shadowPaint.setColor(Color.parseColor("#3b00ff00"));
pathMeasureList = new ArrayList<>();
pathList = new ArrayList<>();
intersectionList = new ArrayList<>();
matrixList = new ArrayList<>();
loopPathList = new ArrayList<>();
valuePath = new Path();
valueList = new ArrayList<>();
circleWidth = UIUtils.dp2px(getContext(),4);
}
@Override
protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < dimensionList.size(); i++) {
pathList.get(i).moveTo(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
pathList.get(i).lineTo(getMeasuredWidth() / 2, getMeasuredHeight() / 2 - UIUtils.dp2px(getContext(), 65));
pathMeasureList.get(i).setPath(pathList.get(i), false);
canvas.drawPath(pathList.get(i), linePaint);
pathMeasureList.get(i).getMatrix(pathMeasureList.get(i).getLength(), matrixList.get(i), PathMeasure.POSITION_MATRIX_FLAG | PathMeasure.TANGENT_MATRIX_FLAG);
// 注意,这里不要使用preRotate和postRotate,因为坐标会乱得离谱
matrixList.get(i).setRotate(360 / dimensionList.size() * i, getMeasuredWidth() / 2, getMeasuredHeight() / 2);
pathList.get(i).transform(matrixList.get(i));
pathMeasureList.get(i).setPath(pathList.get(i), false);
canvas.drawPath(pathList.get(i), linePaint);
}
for (int j = 0; j < scale; j++) {
for (int i = 0; i < pathMeasureList.size(); i++) {
pathMeasureList.get(i).getPosTan(pathMeasureList.get(i).getLength() / scale * (j + 1), intersectionList.get(j).get(i), null);
}
}
for (int i = 0; i < intersectionList.size(); i++) {
for (int j = 0; j < intersectionList.get(i).size(); j++) {
float[] array = intersectionList.get(i).get(j);
if (j == 0) {
loopPathList.get(i).moveTo(array[0], array[1]);
} else {
loopPathList.get(i).lineTo(array[0], array[1]);
}
}
loopPathList.get(i).close();
canvas.drawPath(loopPathList.get(i), linePaint);
}
for (int i = 0; i < dimensionList.size(); i++) {
pathMeasureList.get(i).getPosTan(pathMeasureList.get(i).getLength()/100*dimensionList.get(i).getValue(),valueList.get(i),null);
}
for (int i = 0; i < valueList.size(); i++) {
if(i==0){
valuePath.moveTo(valueList.get(i)[0],valueList.get(i)[1]);
}else{
valuePath.lineTo(valueList.get(i)[0],valueList.get(i)[1]);
}
canvas.drawCircle(valueList.get(i)[0],valueList.get(i)[1],circleWidth,pointPaint);
}
canvas.drawPath(valuePath,shadowPaint);
}
public void setDimensionList(List<DimensionBean> dimensionList, int scale, float maxValue) {
this.scale = scale;
this.maxValue = maxValue;
this.dimensionList = dimensionList;
for (int i = 0; i < dimensionList.size(); i++) {
pathMeasureList.add(new PathMeasure());
pathList.add(new Path());
float[] valueFloat = new float[2];
valueList.add(valueFloat);
matrixList.add(new Matrix());
loopPathList.add(new Path());
}
for (int i = 0; i < scale; i++) {
List<float[]> loopPositionList = new ArrayList<>();
for (int j = 0; j < dimensionList.size(); j++) {
float[] floatArray = new float[2];
loopPositionList.add(floatArray);
}
intersectionList.add(loopPositionList);
}
invalidate();
}
}
Activity中调用
package com.example.kotlintest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.viewpager2.widget.ViewPager2
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var radarChartView = findViewById<RadarChartView>(R.id.radarView)
var dimensionList = mutableListOf<DimensionBean>()
dimensionList.add(DimensionBean(19,"进攻[19]"))
dimensionList.add(DimensionBean(39,"技术[39]"))
dimensionList.add(DimensionBean(59,"战术[59]"))
dimensionList.add(DimensionBean(49,"防守[49]"))
dimensionList.add(DimensionBean(99,"创造力[99]"))
radarChartView.setDimensionList(dimensionList,4,100f)
}
}
package com.example.kotlintest;
public class DimensionBean {
private int value;
private String show;
public DimensionBean(int value, String show) {
this.value = value;
this.show = show;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getShow() {
return show;
}
public void setShow(String show) {
this.show = show;
}
}