Android雷达图(蜘蛛网图)绘制
最近因为项目需求,要实现一款雷达图来表示用户的各种成就值。
雷达图的绘制很简单,只要思路清晰按部就班的绘制就可以了,其中使用得最多,是路径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; //中心Xprivate int centerY; //中心Yprivate 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; //文本画笔...@Overrideprotected 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;ifloat curR = r*i;//当前半径path.reset();for(int j=0;jif(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;ipath.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;ifloat 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;idouble 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类的使用,另外这个控件没有做较好的屏幕适配,大家可以根据自己的需要修改。
到这里就结束啦。
评论
