Android雷达图View

亲爱的各位小伙伴们,我又回来了。前段时间因为工作比较忙,加上一个生活上的事情,文章就没有更新哦。然后自定义饼状图系列酒夭折了。一部分是因为没时间去写,还有一部分原因是因为感觉写不下去了。自己一开始想的太简单了。才发现想要达到那样的效果实在是有太多的坑要去踩。后期一定尽量慢慢的去完善那个控件的。希望小伙伴们支持。

本文所有内容都是自己一个字一个字手打。代码逻辑部分参考http://blog.csdn.net/crazy__chen/article/details/50163693如有问题请指出。谢谢!

进入正题,先看一下效果

Android雷达图View_第1张图片
目前最终效果图.png
目前可以自定义的属性有以下几点:
  1. 雷达网的颜色
  2. 雷达网的分支个数(也就是数据的种类)
  3. 雷达网的层数(数据的值的分层)
  4. 每个选项的点的颜色
  5. 填充区域的颜色
目前待优化有以下几个:
  1. 填充数据问题
  2. 文字标识显示问题
  3. 屏幕适配问题

代码实现

先获取XML文件中的属性。这里有个要注意的问题。也是待优化的地方。XML文件中定义的数据的个数和传入的数据的个数必须要一样,不然会报错。

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

    private void initCifg(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RadarView);
        textColor = typedArray.getColor(R.styleable.RadarView_textPaintColor, Color.BLACK);
        radarColor = typedArray.getColor(R.styleable.RadarView_radarPaintColor, Color.GRAY);
        valueColor = typedArray.getColor(R.styleable.RadarView_valuePaintColor, Color.BLUE);
        levelCount = typedArray.getInt(R.styleable.RadarView_levelCount, 6);
        valueCount = typedArray.getInt(R.styleable.RadarView_valueCount, 6);
        pointColor = typedArray.getColor(R.styleable.RadarView_pointColor, Color.BLUE);
        typedArray.recycle();

    }


    /**
     * 初始化View参数
     */
    private void initView() {

        radarPaint = new Paint();
        radarPaint.setColor(radarColor);
        radarPaint.setStyle(Paint.Style.STROKE);
        textPaint = new Paint();
        textPaint.setTextSize(40);
        textPaint.setColor(Color.BLACK);
        datas = new ArrayList<>();
        valuePaint = new Paint();
        valuePaint.setColor(valueColor);
        datas.add(new RadarViewBean("德",10));
        datas.add(new RadarViewBean("智",20));
        datas.add(new RadarViewBean("体",30));
        datas.add(new RadarViewBean("美",40));
        datas.add(new RadarViewBean("劳",50));
        datas.add(new RadarViewBean("爱",60));
    }

看一下attr中的代码

 
        
        
        
        
        
        
    

确定View显示的位置

雷达图简单来说可以看成是一个圆在界面显示。要保证View在界面上不会有挡住的部分。所以View的宽高要按照空间在XML中的位置的最短的一个属性来设置。

  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        radiusMax = Math.min(w, h) / 2 * 0.7f;//这里乘上0.7f也是进一步防止空间被挡住。因为还要给文字表示留位置,所以缩小的稍微多了一点。
        centerX = w / 2;
        centerY = h / 2;
        postInvalidate();
        super.onSizeChanged(w, h, oldw, oldh);
    }

绘画雷达图背景

  1. 第一步要绘制雷达图背后的网格图。
    以一个点为起点,每隔一定的角度画线。角度是根据值得个数来改变。直到换成一个多边形。
  • 外层循环控制网格线绘制到第几层
  • 内层循环控制每层网格线的绘制
 /**
     * 绘制雷达的层层边框
     *
     * @param canvas
     */
    private void drawRadarShape(Canvas canvas) {
        Path path = new Path();
        float spacing = radiusMax / (count - 1);
        for (int i = 1; i < count; i++) {
            float currtRadius = spacing * i;
            path.reset();
            for (int j = 0; j < valueCount; j++) {
                if (j == 0) {
                    path.moveTo(centerX + currtRadius, centerY);
                } else {
                    float x = (float) (centerX + currtRadius * Math.cos(angle * j));
                    float y = (float) (centerY + currtRadius * Math.sin(angle * j));
                    path.lineTo(x, y);
                }
            }
            path.close();
            canvas.drawPath(path, radarPaint);
        }
    }
  1. 第二部要绘制雷达图向外辐射的线
    以View的中心点为起点,每隔一定的角度画一条线。这个比较简单。不详细说。
  /**
     * 画多边形每个对角线的连线
     *
     * @param canvas
     */
    private void drawRadarLines(Canvas canvas) {
        Path path = new Path();
        for (int i = 0; i < valueCount; i++) {
            path.reset();
            path.moveTo(centerX, centerY);
            float x = (float) (centerX + radiusMax * Math.cos(angle * i));
            float y = (float) (centerY + radiusMax * Math.sin(angle * i));
            path.lineTo(x, y);
            canvas.drawPath(path, radarPaint);
        }
    }
Android雷达图View_第2张图片
效果图2.png

绘制显示标识

绘制文字的过程稍微有点复杂。这里参考了较多别人处理文字的方式。
文字在绘制的时候要考虑到不要遮挡View本身,所以需要考虑到文字所在的位置,一般是按象限来看。同时也需要考虑到文字的长度和高度

这里需要说一下的是 Paint.FontMetrics 这个属性。
这个里面需要注意的文字高度有多个高度,这里在计算文字高度的时候需要注意一下。


    /**
     * 绘制每条线的标识
     *
     * @param canvas
     */
    private void drawRadarText(Canvas canvas) {
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float fontHeight = fontMetrics.descent - fontMetrics.ascent;
        for (int i = 0; i < valueCount; i++) {
            float x = (float) (centerX + (radiusMax + fontHeight / 2) * Math.cos(angle * i));
            float y = (float) (centerY + (radiusMax + fontHeight / 2) * Math.sin(angle * i));
            if (angle * i >= 0 && angle * i <= Math.PI / 2) {//第4象限
                canvas.drawText(datas.get(i).getTitle(), x, y, textPaint);
            } else if (angle * i >= 3 * Math.PI / 2 && angle * i <= Math.PI * 2) {//第3象限
                canvas.drawText(datas.get(i).getTitle(), x, y, textPaint);
            } else if (angle * i > Math.PI / 2 && angle * i <= Math.PI) {//第2象限
                float dis = textPaint.measureText(datas.get(i).getTitle());//文本长度
                canvas.drawText(datas.get(i).getTitle(), x - dis, y, textPaint);
            } else if (angle * i >= Math.PI && angle * i < 3 * Math.PI / 2) {//第1象限
                float dis = textPaint.measureText(datas.get(i).getTitle());//文本长度
                canvas.drawText(datas.get(i).getTitle(), x - dis, y, textPaint);
            }
        }
    }

最后绘制填充区域

  • 这里需要注意把文字笔的属性调一下

valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);

也不是全程都是这个,在画点和线的时候要注意。

/**
     * 画填充区域
     * @param canvas
     */
    private void drawRadarValue(Canvas canvas) {
        Path path = new Path();
        valuePaint.setAlpha(255); //设置透明度的时候可以自己随意设置
        for(int i=0;i

总结

这个控件总的来说还是比较简单的,需要注意的基础点比较多。然后在绘制文字表示的时候需要注意的点也比较多。具体使用下来暂时没有出现问题。如果有问题请回复或者私信联系我修改。谢谢!附上源码。
点我跳转
最后希望大家点击一下喜欢!

你可能感兴趣的:(Android雷达图View)