美文网首页
自定义蜘蛛网图RadarView

自定义蜘蛛网图RadarView

作者: 小玉1991 | 来源:发表于2019-12-04 15:18 被阅读0次

工作中遇到上面的需求,查询资料后,自己做了优化,总结一下

要求还有相关的图层,图层还有边框。


蜘蛛网图1 蜘蛛网图2

先看在页面中的使用方法

            radar_view.setNames(mDiagnosisBean.names);
            radar_view.cleanRegions();
            //图层1
                radar_view.addRegion(R.color.color_99FFE27F, R.color.color_F8D353,
                        R.color.color_E9AD68, lsit1, 12);
            //图层2
                radar_view.addRegion(R.color.color_99B6E89C, R.color.color_39D075,
                        R.color.color_00BA7E, lsit2, 19);
                radar_view.invalidate();

RadarView 直接上代码

public class RadarView extends View {

    private int count = 3; //几边形
    private int layerCount = 5; //层数
    private double angle; //每条边对应的圆心角
    private int centerX; //圆心x
    private int centerY; //圆心y
    private float radius; //半径
    private Paint polygonPaint; //边框paint
    //    private Paint linePaint; //连线paint
    private Paint txtPaint; //文字paint


    private List<String> datas;
    private List<Region> mRegions = new ArrayList<>();


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

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

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

        datas = new ArrayList<>();


        polygonPaint = new Paint();
        polygonPaint.setColor(Color.parseColor("#C4C4C4"));
        polygonPaint.setAntiAlias(true);
        polygonPaint.setStyle(Paint.Style.STROKE);
        polygonPaint.setStrokeWidth(1f);

//        linePaint = new Paint();
//        linePaint.setColor(ContextCompat.getColor(context, android.R.color.background_dark));
//        linePaint.setAntiAlias(true);
//        linePaint.setStyle(Paint.Style.STROKE);
//        linePaint.setStrokeWidth(2f);

    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        radius = Math.min(h, w) / 2 * 0.85f;
        centerX = w / 2;
        centerY = h / 2;
    }

    public void setNames(List<String> list) {
        setNames(list, R.color.local_test_Judge_background, 16);
    }


    public void setNames(List<String> list, int textColor, int size) {
        this.datas.clear();
        this.datas.addAll(list);

        if (datas != null && datas.size() > 0) {
            txtPaint = new Paint();
            txtPaint.setColor(getResources().getColor(textColor));
            txtPaint.setAntiAlias(true);
            txtPaint.setStyle(Paint.Style.STROKE);
            txtPaint.setTextSize(PixelUtil.dp2px(size));
        }
    }

    public void cleanRegions() {
        mRegions.clear();
    }

    public void addRegion(int colorInside, int colorBorder, int colorText, List<Float> list, int sizeText) {
        Region region = new Region();
        region.setColorIn(colorInside);
        region.setColorBorder(colorBorder);
        region.setList(list);
        region.setSizeText(sizeText);
        region.setColorText(colorText);
        mRegions.add(region);
    }

    private void drawRegion(int colorInside, int colorBorder, int textColor, int textSize, List<Float> list, Canvas canvas) {
        Paint paintIn = new Paint();
        paintIn.setColor(getResources().getColor(colorInside));
        paintIn.setStyle(Paint.Style.FILL);
        paintIn.setAntiAlias(true);
        Path path = new Path();


        for (int i = 0; i < list.size(); i++) {
            float curR = list.get(i); //当前位置所在的数值
            curR = curR * radius;
            if (i == 0) {
                path.moveTo(centerX, centerY - curR);
            } else {
                float x = (float) (centerX + Math.sin(angle * i) * curR);
                float y = (float) (centerY - Math.cos(angle * i) * curR);
                path.lineTo(x, y);
            }
        }
        path.close();
        canvas.drawPath(path, paintIn);

        drawBorder(colorBorder, textColor, textSize, list, canvas);

    }

    private int textPerOff = -3;

    private void drawBorder(int colorBorder, int textColor, int textSize, List<Float> list, Canvas canvas) {
        Paint paintBorder = new Paint();
        paintBorder.setColor(getResources().getColor(colorBorder));
        paintBorder.setStyle(Paint.Style.STROKE);
        paintBorder.setAntiAlias(true);

        Paint paint = new Paint();
        paint.setColor(getResources().getColor(textColor));
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);
        paint.setTextSize(PixelUtil.dp2px(textSize));

        Path path = new Path();

        for (int j = 0; j < count; j++) {
            float curR = list.get(j); //当前位置所在的数值
            float height = curR * radius;
            if (j == 0) {
                //第一个点坐标
                path.moveTo(centerX, centerY - height);
                drawPercent(canvas, paint, ((int) curR * 100) + "%", centerX, centerY - height, textPerOff, j);
            } else {
                //顺时针记录其余顶角的点坐标
                float x = (float) (centerX + Math.sin(angle * j) * height);
                float y = (float) (centerY - Math.cos(angle * j) * height);
                path.lineTo(x, y);
                drawPercent(canvas, paint, ((int) curR * 100) + "%", x, y, textPerOff, j);
            }
        }
        path.close();
        canvas.drawPath(path, paintBorder);
    }

    private void drawPercent(Canvas canvas, Paint paint, String text, float x, float y, int off, int i) {
        if (angle * i == 0) {
            //第一个文字位于顶角正上方
            paint.setTextAlign(Paint.Align.CENTER);
            canvas.drawText(text, x, y - dp2px(off), paint);
            paint.setTextAlign(Paint.Align.LEFT);
        } else if (angle * i > 0 && angle * i < Math.PI / 2) {
            //微调
            canvas.drawText(text, x + dp2px(off), y + dp2px(off), paint);
        } else if (angle * i >= Math.PI / 2 && angle * i < Math.PI) {
            //最右下的文字获取到文字的长、宽,按文字长度百分比向左移

            Rect bounds = new Rect();
            paint.getTextBounds(text, 0, text.length(), bounds);
            float height = bounds.bottom - bounds.top;
            float width = paint.measureText(text);
            canvas.drawText(text, x - width * 0.2f, y + height + dp2px(off), paint);
        } else if (angle * i >= Math.PI && angle * i < 3 * Math.PI / 2) {
            //同理最左下的文字获取到文字的长、宽,按文字长度百分比向左移

            Rect bounds = new Rect();
            paint.getTextBounds(text, 0, text.length(), bounds);
            float width = paint.measureText(text);
            float height = bounds.bottom - bounds.top;
            canvas.drawText(text, x - width * 0.8f, y + height + dp2px(off), paint);
        } else if (angle * i >= 3 * Math.PI / 2 && angle * i < 2 * Math.PI) {
            //文字向左移动
            String txt = text;
            float width = paint.measureText(txt);
            canvas.drawText(txt, x - width - dp2px(off), y + dp2px(off), paint);
        }
    }

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

        if (datas != null && datas.size() > 0) {
            count = datas.size();
            //计算圆心角
            angle = Math.PI * 2 / count;
            drawPolygon(canvas);//画边
            drawText(canvas);//描绘文字
            // drawLines(mCanvas);//画线
            //drawRegion(canvas);//覆盖区域
            if (mRegions != null && mRegions.size() > 0) {
                for (Region region : mRegions) {
                    drawRegion(region.getColorIn(), region.getColorBorder(),
                            region.getColorText(), region.getSizeText(),
                            region.getList(), canvas);
                }
            }
        }


    }

    private void drawPolygon(Canvas canvas) {
        Path path = new Path();
        float r = radius / layerCount;
        for (int i = 1; i <= layerCount; i++) {
            float curR = r * i; //当前所在层的半径
            for (int j = 0; j < count; j++) {
                if (j == 0) {
                    //每一层第一个点坐标
                    path.moveTo(centerX, centerY - curR);
                } else {
                    //顺时针记录其余顶角的点坐标
                    float x = (float) (centerX + Math.sin(angle * j) * curR);
                    float y = (float) (centerY - Math.cos(angle * j) * curR);
                    path.lineTo(x, y);
                }
            }
            path.close();
            canvas.drawPath(path, polygonPaint);
        }
    }

    /*private void drawLines(Canvas canvas) {
        float r = radius / layerCount;
        for (int i = 0; i < count; i++) {
            //起始坐标 从中心开始的话 startx=centerX , startY=centerY
            float startX = (float) (centerX + Math.sin(angle * i) * r);
            float startY = (float) (centerY - Math.cos(angle * i) * r);
            //末端坐标
            float endX = (float) (centerX + Math.sin(angle * i) * radius);
            float endY = (float) (centerY - Math.cos(angle * i) * radius);
            canvas.drawLine(startX, startY, endX, endY, linePaint);
        }
    }*/
    private int mTextDistance = 5;

    private void drawText(Canvas canvas) {
        for (int i = 0; i < count; i++) {

            txtPaint.setTextAlign(Paint.Align.CENTER);
            String txt = datas.get(i);
            Rect bounds = new Rect();
            txtPaint.getTextBounds(txt, 0, txt.length(), bounds);
            float height = bounds.bottom - bounds.top;
            float width = txtPaint.measureText(txt);

            mTextDistance= (int) height;

            //获取到雷达图最外边的坐标
            float x = (float) (centerX + Math.sin(angle * i) * (radius + dp2px(mTextDistance)));
            float y = (float) (centerY - Math.cos(angle * i) * (radius + dp2px(mTextDistance)));

            Paint paint = new Paint();
            paint.setColor(Color.RED);
            canvas.drawCircle(x, y,5, paint);

            x = (float) (x + Math.sin(angle * i) * width/2);
//            y = (float) (y - Math.cos(angle * i) * height/2);
            y = y + height / 2;

            canvas.drawText(txt, x, y, txtPaint);
        }
    }

//    private void drawRegion(Canvas canvas) {
//        Path path = new Path();
//        float r = radius / layerCount;//每层的间距
//        for (int i = 0; i < count; i++) {
//            if (i == 0) {
//                path.moveTo(centerX, (float) (centerY - r - (radius - r) * datas.get(i).getValue()));
//            } else {
//                float x = (float) (centerX + Math.sin(angle * i) * ( datas.get(i).getValue() * (radius - r) + r));
//                float y = (float) (centerY - Math.cos(angle * i) * ( datas.get(i).getValue() * (radius - r) + r));
//                path.lineTo(x, y);
//            }
//        }
//        path.close();
//        canvas.drawPath(path, regionColorPaint);
//    }

    private int dp2px(int dp) {
        return PixelUtil.dp2px(dp);
    }

    //设置几边形,**注意:设置几边形需要重新计算圆心角**
    public void setCount(int count) {
        this.count = count;
        angle = (float) (Math.PI * 2 / count);
        invalidate();
    }

    //设置层数
    public void setLayerCount(int layerCount) {
        this.layerCount = layerCount;
        invalidate();
    }


    public static class Region {
        private int colorIn;
        private int colorBorder;
        private int colorText;
        private int sizeText;
        private List<Float> list;

        public int getColorIn() {
            return colorIn;
        }

        public void setColorIn(int colorIn) {
            this.colorIn = colorIn;
        }

        public int getColorBorder() {
            return colorBorder;
        }

        public void setColorBorder(int colorBorder) {
            this.colorBorder = colorBorder;
        }

        public List<Float> getList() {
            return list;
        }

        public void setList(List<Float> list) {
            this.list = list;
        }

        public int getColorText() {
            return colorText;
        }

        public void setColorText(int colorText) {
            this.colorText = colorText;
        }

        public int getSizeText() {
            return sizeText;
        }

        public void setSizeText(int sizeText) {
            this.sizeText = sizeText;
        }
    }
}

相关文章

网友评论

      本文标题:自定义蜘蛛网图RadarView

      本文链接:https://www.haomeiwen.com/subject/jhllgctx.html