自定义View绘制雷达图

就直接上代码啦,注释都写的很详细了的
package com.mvp.viewdemo;

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

/**
 * <h3>Description</h3>
 * <p>
 * 雷达图
 * <p>
 * <h3>Author</h3> cgc
 * <h3>Date</h3> 2016/11/17 13:53
 * <h3>Copyright</h3> Copyright (c)2016 Shenzhen JJshome Technology Co., Ltd. Inc. All rights reserved.
 */
public class RadarView extends View {

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

    public RadarView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RadarView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init();
    }

    /** 绘制连线画笔 */
    private Paint mLienPaint;
    /** 绘制数据点画笔 */
    private Paint mDataPaint;
    /** 绘制文本画笔 */
    private Paint mTextPaint;
    /** 中心点 x */
    private int centreX;
    /** 中心点y */
    private int centreY;
    /** 半径 */
    private float radius = 0;
    /** 数据点半径 */
    private float dataRadius = 10;
    /** 数据区透明值 最大255 不透明 */
    private int dataAlpha = 127;
    /** 字体大小 */
    private int textSize = 38;
    /** 连线颜色 */
    private int lienColor = Color.GRAY;
    /** 数据点颜色 */
    private int dataColor = Color.GREEN;
    /** 数据区颜色 */
    private int dataAreaColor = Color.YELLOW;
    /** 数据点之间的连线颜色 */
    private int dataPointLienColor = Color.RED;
    /** 文本颜色 */
    private int textColor = Color.BLACK;
    /** 雷达图占界面的比例 默认0.8 */
    private float occupyRatio = 0.8f;
    /** 根据数据设置纬度 */
    private boolean isValuesToCount = false;

    /** 纬度数 */
    private int count = 8;
    /** 计算角度 */
    private float angle = (float) (Math.PI * 2 / count);
    /** 最大值 */
    private int maxValue = 100;
    /** 数值 */
    private double[] values = null;


    private void init() {
        //初始化绘制连接的画笔
        mLienPaint = new Paint();
        mLienPaint.setAntiAlias(true);
        mLienPaint.setStyle(Paint.Style.STROKE);
        mLienPaint.setColor(lienColor);
        //初始化绘制数据的画笔
        mDataPaint = new Paint();
        mDataPaint.setAntiAlias(true);
        mDataPaint.setStyle(Paint.Style.STROKE);
        mDataPaint.setColor(dataColor);
        //初始化绘制文字的画笔
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.STROKE);
        mTextPaint.setColor(textColor);
        mTextPaint.setTextSize(textSize);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        radius = Math.min(w, h) / 2 * occupyRatio;
        centreX = w / 2;
        centreY = h / 2;
//        postInvalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        drawLien(canvas);
        drawToLien(canvas);
        drawText(canvas);
        if (values != null && values.length > 0) {
            drawValue(canvas);
        }
    }

    /**
     * 绘制数据区
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,16:40
     * <h3>UpdateTime</h3> 2016/11/17,16:40
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param canvas
     */
    private void drawValue(Canvas canvas) {
        Path path = new Path();
        for (int i = 0; i < count; i++) {
            //计算数据值所占的比例
            double percent = values[i] / maxValue;
            //计算坐标
            float x = (float) (centreX + radius * Math.cos(angle * i) * percent);
            float y = (float) (centreY + radius * Math.sin(angle * i) * percent);
            if (i == 0) {//设置起点
                path.moveTo(x, centreY);
            } else {
                //记录数据点
                if (values[i] != 0) {
                    path.lineTo(x, y);
                }
            }
            //绘制数据点
            if (values[i] != 0) {
                mDataPaint.setStyle(Paint.Style.FILL);
                mDataPaint.setColor(dataColor);
                canvas.drawCircle(x, y, dataRadius, mDataPaint);
            }
        }
        //闭合路径,连接数据点
        path.close();
        mDataPaint.setColor(dataPointLienColor);
        mDataPaint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(path, mDataPaint);
        //绘制数据点之间区域的面积
        mDataPaint.setColor(dataAreaColor);
        mDataPaint.setAlpha(dataAlpha);
        mDataPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(path, mDataPaint);
    }

    /**
     * 数据点的半径
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,16:56
     * <h3>UpdateTime</h3> 2016/11/17,16:56
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param dataRadius
     */
    public void setDataRadius(float dataRadius) {
        this.dataRadius = dataRadius;
    }

    /**
     * 数据区域的透明值
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,16:56
     * <h3>UpdateTime</h3> 2016/11/17,16:56
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param dataAlpha 1-255 1为全透明,255未透明
     */
    public void setDataAlpha(int dataAlpha) {
        this.dataAlpha = dataAlpha;
    }

    /**
     * 设置字体大小
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:32
     * <h3>UpdateTime</h3> 2016/11/17,17:32
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param textSize
     */
    public void setTextSize(int textSize) {
        this.textSize = textSize;
    }

    /**
     * 设置雷达图连接颜色
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:33
     * <h3>UpdateTime</h3> 2016/11/17,17:33
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param lienColor
     */
    public void setLienColor(int lienColor) {
        mLienPaint.setColor(lienColor);
    }

    /**
     * 设置数据点颜色
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:33
     * <h3>UpdateTime</h3> 2016/11/17,17:33
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param dataColor
     */
    public void setDataColor(int dataColor) {
        this.dataColor = dataColor;
    }

    /**
     * 设置数据区颜色
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:34
     * <h3>UpdateTime</h3> 2016/11/17,17:34
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param dataAreaColor
     */
    public void setDataAreaColor(int dataAreaColor) {
        this.dataAreaColor = dataAreaColor;
    }

    /**
     * 设置数据点颜色
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:34
     * <h3>UpdateTime</h3> 2016/11/17,17:34
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param dataPointLienColor
     */
    public void setDataPointLienColor(int dataPointLienColor) {
        this.dataPointLienColor = dataPointLienColor;
    }

    /**
     * 设置字体颜色
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:34
     * <h3>UpdateTime</h3> 2016/11/17,17:34
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param textColor
     */
    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    /**
     * 雷达图占界面的比例 默认0.8
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:34
     * <h3>UpdateTime</h3> 2016/11/17,17:34
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param occupyRatio
     */
    public void setOccupyRatio(float occupyRatio) {
        this.occupyRatio = occupyRatio;
    }

    /**
     * 设置纬度值
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:35
     * <h3>UpdateTime</h3> 2016/11/17,17:35
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param count
     */
    public void setCount(int count) {
        if (!isValuesToCount) {
            this.count = count;
        }
    }

    /**
     * 设置最大值
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:35
     * <h3>UpdateTime</h3> 2016/11/17,17:35
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param maxValue
     */
    public void setMaxValue(int maxValue) {
        this.maxValue = maxValue;
    }

    /**
     * 数值
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:35
     * <h3>UpdateTime</h3> 2016/11/17,17:35
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param values
     */
    public void setValues(double[] values) {
        this.values = values;
        this.count = values.length;
    }

    /**
     * 是否根据数值设置纬度
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:39
     * <h3>UpdateTime</h3> 2016/11/17,17:39
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param values          数据值
     * @param isValuesToCount 是否根据数据值数量设置纬度数 true(如果是true setCount 设置纬度将失效) false 不是
     */
    public void setValues(double[] values, boolean isValuesToCount) {
        this.values = values;
        if (isValuesToCount) {
            this.count = values.length;
        }
        this.isValuesToCount = isValuesToCount;
    }

    /**
     * 绘制雷达图
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,17:36
     * <h3>UpdateTime</h3> 2016/11/17,17:36
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     */
    public void startInvalidate() {
        angle = (float) (Math.PI * 2 / count);
        invalidate();
    }

    /**
     * 绘制文本
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,16:42
     * <h3>UpdateTime</h3> 2016/11/17,16:42
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param canvas
     */
    private void drawText(Canvas canvas) {
        //获取画笔的适量
        Paint.FontMetrics fm = mTextPaint.getFontMetrics();
        //计算文本的高度
        float fontHeight = fm.descent - fm.ascent;
        for (int i = 0; i < count; i++) {
            //计算坐标
            float x = (float) (centreX + (radius + fontHeight / 2) * Math.cos(angle * i));
            float y = (float) (centreY + (radius + fontHeight / 2) * Math.sin(angle * i));
            if (i == 0) {//绘制第一项
                canvas.drawText(i + "", x, y + (fontHeight / 2) / 2, mTextPaint);
            } else if (i == 3) {//绘制第三项
                canvas.drawText(i + "", x - 20, y + (fontHeight / 2) / 2, mTextPaint);
            } else if (i == 2 || i == 1) {//绘制第二,一项
                canvas.drawText(i + "", x, y + (fontHeight / 2), mTextPaint);
            } else {
                canvas.drawText(i + "", x, y, mTextPaint);
            }
        }
    }

    /**
     * 绘制雷达图的层次
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,16:44
     * <h3>UpdateTime</h3> 2016/11/17,16:44
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param canvas
     */
    private void drawLien(Canvas canvas) {
        //层次之间的距离
        float r = radius / (count - 1);
        //绘制路径
        Path path = new Path();
        for (int i = 1; i < count; i++) {
            //层次的半径
            float newRadius = r * i;
            path.reset();
            for (int j = 0; j < count; j++) {
                if (j == 0) {//绘制起点
                    path.moveTo(centreX + newRadius, centreY);
                } else {
                    //计算角度的坐标
                    float x = (float) (centreX + newRadius * Math.cos(angle * j));
                    float y = (float) (centreY + newRadius * Math.sin(angle * j));
                    //进行连线
                    path.lineTo(x, y);
                }
            }
            //闭合路径
            path.close();
            canvas.drawPath(path, mLienPaint);
        }
    }

    /**
     * 绘制中心点到纬度点的连接
     * <p>
     * <h3>Version</h3> 1.0
     * <h3>CreateTime</h3> 2016/11/17,16:44
     * <h3>UpdateTime</h3> 2016/11/17,16:44
     * <h3>CreateAuthor</h3> cgc
     * <h3>UpdateAuthor</h3> cgc
     * <h3>UpdateInfo</h3> (此处输入修改内容,若无修改可不写.)
     *
     * @param canvas
     */
    private void drawToLien(Canvas canvas) {
        Path path = new Path();
        for (int i = 0; i < count; i++) {
            path.reset();
            path.moveTo(centreX, centreY);
            float x = (float) (centreX + radius * Math.cos(angle * i));
            float y = (float) (centreY + radius * Math.sin(angle * i));
            path.lineTo(x, y);
            path.close();
            canvas.drawPath(path, mLienPaint);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值