项目中有图表的绘制 折线图,k线图,柱状图跟雷达图
今天就写一写如何实现自定义view来实现雷达图效果
1.设置变量
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 = {3,3,3,3,3,3}; //各维度分值 private ArrayList<Float> data = new ArrayList<Float>(); //各维度值 private float maxValue = 5; //数据最大值 private Paint mainPaint; //雷达区画笔 private Paint innerValuePaint; //数据区画笔 private Paint textPaint; //文本画笔 private Paint outerValuePaint; //雷达区边框画笔 private float circleRadius = 2; //圆点半径 private int lableCount = 6; //Y轴值个数 private int innerAlpha = 166; //蜘蛛网局部透明度 private float strokeWidth = 2; //蜘蛛网边框宽度 private boolean drawLabels = false; //绘制轴值 private boolean showValueText = false; //是否显示轴上的值 private float circleZero =(float) Math.PI/2; ; //初始角度为90度
2.初始化画笔
private void init() { count = titles.length; mainPaint = new Paint(); mainPaint.setAntiAlias(true); mainPaint.setColor(Color.GRAY); mainPaint.setStyle(Paint.Style.STROKE); innerValuePaint = new Paint(); innerValuePaint.setAntiAlias(true); innerValuePaint.setColor(Color.BLUE); innerValuePaint.setStyle(Paint.Style.FILL); outerValuePaint = new Paint(); outerValuePaint.setAntiAlias(true); outerValuePaint.setColor(Color.BLUE); outerValuePaint.setStyle(Paint.Style.STROKE); textPaint = new Paint(); textPaint.setTextSize(14); textPaint.setStyle(Paint.Style.FILL); textPaint.setColor(Color.BLACK); }
3.设置雷达图大小(设置雷达半径)
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { radius = Math.min(h, w)/2*0.8f; centerX = w/2; centerY = h/2; postInvalidate(); super.onSizeChanged(w, h, oldw, oldh); }
4.绘制正多边形
/** * 绘制正多边形 */ private void drawPolygon(Canvas canvas){ Path path = new Path(); float r = radius/(lableCount-1); for(int i=1;i<lableCount;i++){ float curR = r*i; path.reset(); for(int j=0;j<count;j++){ if(j==0){ path.moveTo(centerX,centerY-curR); if(drawLabels){ String text =String.valueOf(Float.valueOf((maxValue/(lableCount-1))*i)); float dis = textPaint.measureText(text);//文本长度 canvas.drawText(text,centerX,centerY-curR,textPaint); } }else{ float x = (float) (centerX+curR*Math.cos(angle*j-circleZero)); float y = (float) (centerY+curR*Math.sin(angle*j-circleZero)); 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<count;i++){ path.reset(); path.moveTo(centerX, centerY); float x = (float) (centerX+radius*Math.cos(angle*i-circleZero)); float y = (float) (centerY+radius*Math.sin(angle*i-circleZero)); path.lineTo(x, y); canvas.drawPath(path, mainPaint); } }
6.绘制标签文字
/** * 绘制文字 * @param canvas */ private void drawText(Canvas canvas){ Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); float fontHeight = fontMetrics.descent - fontMetrics.ascent; for(int i=0;i<count;i++){ float x = (float) (centerX+(radius+fontHeight/2)*Math.cos(angle*i-circleZero)); float y = (float) (centerY+(radius+fontHeight/2)*Math.sin(angle*i-circleZero)); float dis = textPaint.measureText(titles[i]);//文本长度 if(i < count/2 && i > 0 ){//第12象限 canvas.drawText(titles[i], x,y,textPaint); }else if(i > count/2){//第34象限 canvas.drawText(titles[i], x-dis,y,textPaint); }else if(i == 0){ canvas.drawText(titles[i], x-dis/2,y,textPaint); }else if(i == count/2){ canvas.drawText(titles[i], x-dis/2,y+15,textPaint); } } }
7.设置雷达区域
/** * 绘制区域 * @param canvas */ private void drawRegion(Canvas canvas){ Path path = new Path(); innerValuePaint.setAlpha(255); float x0 = centerX,y0 = centerY; for(int i=0;i<count;i++){ double percent = data.get(i)/maxValue; float x = (float) (centerX+radius*Math.cos(angle*i-circleZero)*percent); float y = (float) (centerY+radius*Math.sin(angle*i-circleZero)*percent); if(i==0){ path.moveTo(centerX, y); x0 = x; y0 = y; }else { path.lineTo(x,y); } if(i == count-1){ path.lineTo(x0,y0); } //绘制小圆点 canvas.drawCircle(x,y,circleRadius,outerValuePaint); if(showValueText){ float dis = textPaint.measureText(String.valueOf(data.get(i)));//文本长度 if(i < count/2 && i > 0 ){//第12象限 canvas.drawText(String.valueOf(data.get(i)), x,y,textPaint); }else if(i > count/2){//第34象限 canvas.drawText(String.valueOf(data.get(i)), x-dis,y,textPaint); }else if(i == 0){ canvas.drawText(String.valueOf(data.get(i)), x-dis/2,y,textPaint); }else if(i == count/2){ canvas.drawText(String.valueOf(data.get(i)), x-dis/2,y+15,textPaint); } } } innerValuePaint.setAlpha(innerAlpha); canvas.drawPath(path, innerValuePaint); //绘制填充区域 outerValuePaint.setAlpha(255); outerValuePaint.setStrokeWidth(strokeWidth); canvas.drawPath(path, outerValuePaint); }
完整代码如下:
package com.zhuhao.finance.view; 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; import java.util.ArrayList; /** * Created by gaoli on 2017/7/12. */ 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 = {3,3,3,3,3,3}; //各维度分值 private ArrayList<Float> data = new ArrayList<Float>(); //各维度值 private float maxValue = 5; //数据最大值 private Paint mainPaint; //雷达区画笔 private Paint innerValuePaint; //数据区画笔 private Paint textPaint; //文本画笔 private Paint outerValuePaint; //雷达区边框画笔 private float circleRadius = 2; //圆点半径 private int lableCount = 6; //Y轴值个数 private int innerAlpha = 166; //蜘蛛网局部透明度 private float strokeWidth = 2; //蜘蛛网边框宽度 private boolean drawLabels = false; //绘制轴值 private boolean showValueText = false; //是否显示轴上的值 private float circleZero =(float) Math.PI/2; ; //初始角度为90度 public void setCircleRadius(float circleRadius) { this.circleRadius = circleRadius; } public RadarView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public RadarView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RadarView(Context context) { super(context); init(); } //初始化 private void init() { count = titles.length; mainPaint = new Paint(); mainPaint.setAntiAlias(true); mainPaint.setColor(Color.GRAY); mainPaint.setStyle(Paint.Style.STROKE); innerValuePaint = new Paint(); innerValuePaint.setAntiAlias(true); innerValuePaint.setColor(Color.BLUE); innerValuePaint.setStyle(Paint.Style.FILL); outerValuePaint = new Paint(); outerValuePaint.setAntiAlias(true); outerValuePaint.setColor(Color.BLUE); outerValuePaint.setStyle(Paint.Style.STROKE); textPaint = new Paint(); textPaint.setTextSize(14); textPaint.setStyle(Paint.Style.FILL); textPaint.setColor(Color.BLACK); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { radius = Math.min(h, w)/2*0.8f; centerX = w/2; centerY = h/2; postInvalidate(); super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { drawPolygon(canvas); drawLines(canvas); drawText(canvas); drawRegion(canvas); } /** * 绘制正多边形 */ private void drawPolygon(Canvas canvas){ Path path = new Path(); float r = radius/(lableCount-1); for(int i=1;i<lableCount;i++){ float curR = r*i; path.reset(); for(int j=0;j<count;j++){ if(j==0){ path.moveTo(centerX,centerY-curR); if(drawLabels){ String text =String.valueOf(Float.valueOf((maxValue/(lableCount-1))*i)); float dis = textPaint.measureText(text);//文本长度 canvas.drawText(text,centerX,centerY-curR,textPaint); } }else{ float x = (float) (centerX+curR*Math.cos(angle*j-circleZero)); float y = (float) (centerY+curR*Math.sin(angle*j-circleZero)); path.lineTo(x,y); } } path.close(); canvas.drawPath(path, mainPaint); } } /** * 绘制直线 */ private void drawLines(Canvas canvas){ Path path = new Path(); for(int i=0;i<count;i++){ path.reset(); path.moveTo(centerX, centerY); float x = (float) (centerX+radius*Math.cos(angle*i-circleZero)); float y = (float) (centerY+radius*Math.sin(angle*i-circleZero)); path.lineTo(x, y); canvas.drawPath(path, mainPaint); } } /** * 绘制文字 * @param canvas */ private void drawText(Canvas canvas){ Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); float fontHeight = fontMetrics.descent - fontMetrics.ascent; for(int i=0;i<count;i++){ float x = (float) (centerX+(radius+fontHeight/2)*Math.cos(angle*i-circleZero)); float y = (float) (centerY+(radius+fontHeight/2)*Math.sin(angle*i-circleZero)); float dis = textPaint.measureText(titles[i]);//文本长度 if(i < count/2 && i > 0 ){//第12象限 canvas.drawText(titles[i], x,y,textPaint); }else if(i > count/2){//第34象限 canvas.drawText(titles[i], x-dis,y,textPaint); }else if(i == 0){ canvas.drawText(titles[i], x-dis/2,y,textPaint); }else if(i == count/2){ canvas.drawText(titles[i], x-dis/2,y+15,textPaint); } } } /** * 绘制区域 * @param canvas */ private void drawRegion(Canvas canvas){ Path path = new Path(); innerValuePaint.setAlpha(255); float x0 = centerX,y0 = centerY; for(int i=0;i<count;i++){ double percent = data.get(i)/maxValue; float x = (float) (centerX+radius*Math.cos(angle*i-circleZero)*percent); float y = (float) (centerY+radius*Math.sin(angle*i-circleZero)*percent); if(i==0){ path.moveTo(centerX, y); x0 = x; y0 = y; }else { path.lineTo(x,y); } if(i == count-1){ path.lineTo(x0,y0); } //绘制小圆点 canvas.drawCircle(x,y,circleRadius,outerValuePaint); if(showValueText){ float dis = textPaint.measureText(String.valueOf(data.get(i)));//文本长度 if(i < count/2 && i > 0 ){//第12象限 canvas.drawText(String.valueOf(data.get(i)), x,y,textPaint); }else if(i > count/2){//第34象限 canvas.drawText(String.valueOf(data.get(i)), x-dis,y,textPaint); }else if(i == 0){ canvas.drawText(String.valueOf(data.get(i)), x-dis/2,y,textPaint); }else if(i == count/2){ canvas.drawText(String.valueOf(data.get(i)), x-dis/2,y+15,textPaint); } } } innerValuePaint.setAlpha(innerAlpha); canvas.drawPath(path, innerValuePaint); //绘制填充区域 outerValuePaint.setAlpha(255); outerValuePaint.setStrokeWidth(strokeWidth); canvas.drawPath(path, outerValuePaint); } //设置标题 public void setTitles(String[] titles) { this.titles = titles; } //设置数值 public void setData(ArrayList<Float> data) { this.data = data; } public float getMaxValue() { return maxValue; } //设置最大数值 public void setMaxValue(float maxValue) { this.maxValue = maxValue; } //设置蜘蛛网颜色 public void setMainPaintColor(int color){ mainPaint.setColor(color); } //设置蜘蛛网透明度 public void setMainPaintAlpha(int alpha){ mainPaint.setAlpha(alpha); } //设置蜘蛛网区域内透明度 public void setValuePaintAlpha(int alpha){ innerValuePaint.setAlpha(alpha); } //设置标题颜色 public void setTextPaintColor(int color){ textPaint.setColor(color); } //设置覆盖局域颜色 public void setValuePaintColor(int color){ innerValuePaint.setColor(color); outerValuePaint.setColor(color); } //设置字体大小 public void setTextPaintTextSize(float size){ textPaint.setTextSize(size); } public void setLableCount(int lableCount) { this.lableCount = lableCount; } public void setInnerAlpha(int innerAlpha) { this.innerAlpha = innerAlpha; } public void setStrokeWidth(float strokeWidth) { this.strokeWidth = strokeWidth; } public void setDrawLabels(boolean drawLabels) { this.drawLabels = drawLabels; } public void setShowValueText(boolean showValueText) { this.showValueText = showValueText; } }
activity中
@BindView(R.id.rate_chart_radar) RadarView mChart;
private void initRadar() { String[] mActivities = new String[]{"商业模式", "核心壁垒", "团队结构", "运营管理", "盈利能力","成长能力"}; mChart.setTitles(mActivities); ArrayList<Float> data = new ArrayList<>(); data.add(1.5f); data.add(4f); data.add(3.8f); data.add(2.2f); data.add(3.0f); data.add(4.5f); mChart.setData(data); mChart.setMaxValue(5); mChart.setValuePaintColor(Color.rgb(239,83,80)); mChart.setStrokeWidth(3f); mChart.setMainPaintColor(Color.GRAY); mChart.setCircleRadius(1f); mChart.setTextPaintTextSize(28); mChart.setInnerAlpha(166); mChart.setLableCount(6); mChart.setDrawLabels(false); mChart.setShowValueText(true); mChart.invalidate(); }