Android雷达图(蜘蛛网图)绘制

龙旋

共 1978字,需浏览 4分钟

 ·

2022-03-23 11:12

最近因为项目需求,要实现一款雷达图来表示用户的各种成就值。


雷达图的绘制很简单,只要思路清晰按部就班的绘制就可以了,其中使用得最多,是路径path类的使用,使用这个类可以让我们更加方便地绘制出正多边形等效果。


效果图如下:

使用方式


使用方式很简单,只要在布局文件里面,直接使用这个控件就好了,记得给它设置一个合适的具体的大小。


另外可以控制绘制的是多少边形,通过提供的一些public方法,可以设置画笔颜色等,当然大家也可以按照自己的需求去修改啦。

    //设置标题    public void setTitles(String[] titles) {        this.titles = titles;    }
//设置数值 public void setData(double[] data) { this.data = data; }
//设置最大数值 public void setMaxValue(float maxValue) { this.maxValue = maxValue; }
//设置蜘蛛网颜色 public void setMainPaintColor(int color){ mainPaint.setColor(color); }
//设置标题颜色 public void setTextPaintColor(int color){ textPaint.setColor(color); }
//设置覆盖局域颜色 public void setValuePaintColor(int color){ valuePaint.setColor(color); }


具体实现


1、获得布局中心


我们在onSizeChanged(int w, int h, int oldw, int oldh)方法里面,根据View的长宽,获取整个布局的中心坐标,因为整个雷达都是以整个中心开始绘制的。

public class RadarView extends View {    private int count = 6;                //数据个数      private float angle = (float) (Math.PI*2/count);         private float radius;                   //网格最大半径      private int centerX;                  //中心X      private int centerY;                  //中心Y      private String[] titles = {"a","b","c","d","e","f"};    private double[] data = {100,60,60,60,100,50,10,20}; //各维度分值      private float maxValue = 100;             //数据最大值    private Paint mainPaint;                //雷达区画笔      private Paint valuePaint;               //数据区画笔      private Paint textPaint;                //文本画笔          ...    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        radius = Math.min(h, w)/2*0.9f;        //中心坐标        centerX = w/2;        centerY = h/2;        postInvalidate();        super.onSizeChanged(w, h, oldw, oldh);    }    ...}


2、绘制蜘蛛网络

     /**     * 绘制正多边形     */    private void drawPolygon(Canvas canvas){        Path path = new Path();        float r = radius/(count-1);//r是蜘蛛丝之间的间距        for(int i=1;i            float curR = r*i;//当前半径            path.reset();            for(int j=0;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);        }    }

3、绘制从中心到末端的直线


同样根据半径,计算出每个末端坐标

     /**     * 绘制直线     */    private void drawLines(Canvas canvas){        Path path = new Path();        for(int i=0;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);        }    }


4、绘制文本


对于文本的绘制,首先要找到末端的坐标,由于末端和文本有一定距离,给每个末端加上这个距离以后,再绘制文本。


另外,当文本在左边时,由于不希望文本和蜘蛛网交叉,我们可以先计算出文本的长度,然后使起始绘制坐标向左偏移这个长度。

     /**     * 绘制文字     * @param canvas     */    private void drawText(Canvas canvas){        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();        float fontHeight = fontMetrics.descent - fontMetrics.ascent;        for(int i=0;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);            }        }    }

5、绘制覆盖区域


覆盖区域,只要使用path记录下坐标点,然后设

valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);


使path包围区域被填充

     /**     * 绘制区域     * @param canvas     */    private void drawRegion(Canvas canvas){        Path path = new Path();        valuePaint.setAlpha(255);        for(int i=0;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);    }


本篇文章主要是path类的使用,另外这个控件没有做较好的屏幕适配,大家可以根据自己的需要修改。


到这里就结束啦。

浏览 133
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报