Android自定义View实现雷达统计图

2023年7月11日10:07:57

效果展示

Android自定义View实现雷达统计图

代码实现

package com.soface.chartdemo.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import java.util.List;

public class RadarChartView2 extends View {

    public RadarChartView2(Context context) {
        this(context,null);
    }

    public RadarChartView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public RadarChartView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    private int widthMode;
    private int heightMode;
    private int widthSize;
    private int heightSize;
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        widthMode = MeasureSpec.getMode(widthMeasureSpec);
        heightMode = MeasureSpec.getMode(heightMeasureSpec);
        widthSize = MeasureSpec.getSize(widthMeasureSpec);
        heightSize = MeasureSpec.getSize(heightMeasureSpec);

        intiConstant();

        initPaint();
    }

    private float RADIUS =0;
    private float cX=0;
    private float cY=0;
    private float LADDER=5;//阶梯数
    private float DATA_MAX=100;//数据最大值
    private void intiConstant() {
        if (widthSize>heightSize){
            RADIUS =heightSize/2f-20;
        }else {
            RADIUS =widthSize/2f-20;
        }
        cX=widthSize/2f;
        cY=heightSize/2f;
    }

    private Paint linePaint1;
    private Paint textPaint;
    private Paint dataPaint;
    private void initPaint() {
        linePaint1 =new Paint();
        linePaint1.setColor(Color.parseColor("#8F8F8F"));
        linePaint1.setStyle(Paint.Style.STROKE);//不加这个不显示
        linePaint1.setStrokeWidth(2);
        linePaint1.setAntiAlias(true);//抗锯齿功能
        PathEffect effects = new DashPathEffect(new float[]{5, 10}, 0);//设置绘制虚线
        linePaint1.setPathEffect(effects);

        textPaint =new Paint();
        textPaint.setColor(Color.parseColor("#393939"));
        textPaint.setTextSize(30);
        linePaint1.setStrokeWidth(2);

        dataPaint =new Paint();
        dataPaint.setColor(Color.parseColor("#03A9F4"));
        dataPaint.setStyle(Paint.Style.STROKE);//不加这个不显示
        dataPaint.setStrokeWidth(4);
        dataPaint.setAntiAlias(true);//抗锯齿功能
        dataPaint.setStyle(Paint.Style.FILL_AND_STROKE); //设置绘图模式 扫描 FILL_AND_STROKE
        dataPaint.setStrokeJoin(Paint.Join.ROUND); //设置线条闭合模式 MITER
    }

    private List<Integer> dataList;
    public void setData(List<Integer> list){
        dataList=list;
        postInvalidate();
    }

    private List<String> functionsList;
    private String unit="";//单位
    public void setFunction(List<String> list,String unit){
        functionsList=list;
        this.unit=unit;
        postInvalidate();
    }

    private float onceAngle=0;
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (functionsList==null || functionsList.size()==0)return;
        if (dataList==null || dataList.size()==0)return;
        if (dataList.size() != functionsList.size())return;

        float functionsSize=functionsList.size();
        onceAngle=360/functionsSize;

        for (int k=0;k<functionsList.size();k++){
            //绘制角度分割线
            float lineEndX = cX + RADIUS * (float) Math.cos((k*onceAngle) / 180 * Math.PI);
            float lineEndY = cY + RADIUS * (float) Math.sin((k*onceAngle) / 180 * Math.PI);
            canvas.drawLine(cX,cY,lineEndX,lineEndY,linePaint1);

            //绘制功能项名称
            if (lineEndX>cX){
                //在圆心右侧
                textPaint.setColor(Color.parseColor("#393939"));
                canvas.drawText(functionsList.get(k),lineEndX+40,lineEndY,textPaint);
            }else {
                //在圆心左侧
                textPaint.setColor(Color.parseColor("#393939"));
                canvas.drawText(functionsList.get(k),lineEndX-80,lineEndY,textPaint);
            }

        }

        float onceLadderRadius=RADIUS/LADDER;
        int ladderData= (int) (DATA_MAX/LADDER);
        for (int k=0;k<LADDER;k++){

            //绘制刻度
            float textX = cX + (onceLadderRadius*k) * (float) Math.cos((0) / 180 * Math.PI);
            float textY = cY + (onceLadderRadius*k) * (float) Math.sin((0) / 180 * Math.PI);
            if (k==LADDER-1){
                textPaint.setColor(Color.parseColor("#FF5722"));
                canvas.drawText(ladderData*k+"("+unit+")",textX,textY,textPaint);
            }else {
                textPaint.setColor(Color.parseColor("#FF5722"));
                canvas.drawText(ladderData*k+"",textX,textY,textPaint);
            }
        }

        for (int k=0;k<LADDER;k++){

            if (k==0)linePaint1.setColor(Color.parseColor("#FF5722"));
            if (k==1)linePaint1.setColor(Color.parseColor("#FF9800"));
            if (k==2)linePaint1.setColor(Color.parseColor("#CDDC39"));
            if (k==3)linePaint1.setColor(Color.parseColor("#4CAF50"));
            if (k==4)linePaint1.setColor(Color.parseColor("#03A9F4"));
            if (k>=5)linePaint1.setColor(Color.parseColor("#8F8F8F"));

            for (int a=0;a<functionsList.size();a++){

                float startX=cX + (onceLadderRadius*k) * (float) Math.cos((a*onceAngle) / 180 * Math.PI);
                float startY=cY + (onceLadderRadius*k) * (float) Math.sin((a*onceAngle) / 180 * Math.PI);

                float endX=cX + (onceLadderRadius*k) * (float) Math.cos(((a+1)*onceAngle) / 180 * Math.PI);
                float endY=cY + (onceLadderRadius*k) * (float) Math.sin(((a+1)*onceAngle) / 180 * Math.PI);

                Path path=new Path();
                path.moveTo(startX,startY);
                path.lineTo(endX,endY);
                //画线连接下一个点
                canvas.drawPath(path,linePaint1);

            }

        }

        //======================绘制数据=============================================================
        float dataStep=RADIUS/DATA_MAX;
        for (int k=0;k<dataList.size();k++){

            if (k!=dataList.size()-1){
                float startX = cX + (dataStep*dataList.get(k)) * (float) Math.cos((k*onceAngle) / 180 * Math.PI);
                float startY = cY + (dataStep*dataList.get(k)) * (float) Math.sin((k*onceAngle) / 180 * Math.PI);

                float endX = cX + (dataStep*dataList.get(k+1)) * (float) Math.cos(((k+1)*onceAngle) / 180 * Math.PI);
                float endY = cY + (dataStep*dataList.get(k+1)) * (float) Math.sin(((k+1)*onceAngle) / 180 * Math.PI);

                Path path=new Path();
                path.moveTo(startX,startY);
                path.lineTo(endX,endY);
                //画线连接下一个点
                canvas.drawPath(path,dataPaint);

                //画一个点
                canvas.drawCircle(startX,startY,6,dataPaint);
            }else {
                //最后一次画回原点
                float startX = cX + (dataStep*dataList.get(k)) * (float) Math.cos((k*onceAngle) / 180 * Math.PI);
                float startY = cY + (dataStep*dataList.get(k)) * (float) Math.sin((k*onceAngle) / 180 * Math.PI);

                float endX = cX + (dataStep*dataList.get(0)) * (float) Math.cos((0*onceAngle) / 180 * Math.PI);
                float endY = cY + (dataStep*dataList.get(0)) * (float) Math.sin((0*onceAngle) / 180 * Math.PI);

                Path path=new Path();
                path.moveTo(startX,startY);
                path.lineTo(endX,endY);
                //画线连接下一个点
                canvas.drawPath(path,dataPaint);

                //画一个点
                canvas.drawCircle(startX,startY,6,dataPaint);
            }


        }

    }
}

使用方法

  1. 在xml中引用
<com.soface.chartdemo.view.RadarChartView2
                android:id="@+id/radar2"
                android:layout_margin="20px"
                android:layout_width="match_parent"
                android:layout_height="600px"/>
  1. 注入数据
private List<

  • 作者:绝命三郎
  • 原文链接:https://blog.csdn.net/qq_41008818/article/details/128489608
    更新时间:2023年7月11日10:07:57 ,共 5956 字。