您的位置:首页 > 其它

自定义View练习 - 雷达信用图表

2017-06-03 23:53 253 查看

自定义View练习 - 雷达信用图表

练习来源

Android自定义控件 芝麻信用分雷达图

练习的github:https://github.com/alidili/SesameCreditScore

最终效果图



思路

绘制多边形

绘制连接线

绘制填充区域

绘制总分数

绘制标题和图标

实现过程

0. 定义变量

//数据的数量
private int dataCount;
//弧度
private float radian;
//多边形的外接圆的半径
private int radius;
//中心点x
private int centerX;
//中心点y
private int centerY;

private List<CreditBean> creditBeans;
//最大分值
public int maxScore;

private Paint linePaint;
private Paint regionPaint;
private Paint totalScorePaint;
private Paint titlePaint;


1. 计算点坐标

计算坐标的示意图



/**
* 获得点坐标
*/
public Point getPoint(int index) {
return getPoint(index, 1);
}

/**
* 获得点坐标,percent为百分比,用于获得填充区域和文字等的坐标位置.
* 坐标的计算是重难点. 可以画图分析.
*/
public Point getPoint(int index, float percent) {
int x = 0;
int y = 0;
if (index == 0) {
x = (int) (centerX + radius * Math.sin(radian) * percent);
y = (int) (centerY - radius * Math.cos(radian) * percent);
} else if (index == 1) {
x = (int) (centerX + radius * Math.sin(radian * 1.0f / 2) * percent);
y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent);
} else if (index == 2) {
x = (int) (centerX - radius * Math.sin(radian * 1.0f / 2) * percent);
y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent);
} else if (index == 3) {
x = (int) (centerX - radius * Math.sin(radian) * percent);
y = (int) (centerY - radius * Math.cos(radian) * percent);
} else if (index == 4) {
x = centerX;
y = (int) (centerY - radius * percent);
}
return new Point(x, y);
}


2. 绘制过程

@Override
protected void onDraw(Canvas canvas) {
//绘制多边形
drawPolygon(canvas);
//绘制连接线
drawLines(canvas);
//绘制填充区域
drawRegion(canvas);
//绘制总分数
drawTotalScore(canvas);
//绘制标题和图标
drawTitleAndIcons(canvas);
}


绘制多边形

这里注意需要闭合路径

/**
* 绘制多边形
*/
private void drawPolygon(Canvas canvas) {
Path polygonPath = new Path();
for (int i = 0; i < dataCount; i++) {
if (i == 0) {
polygonPath.moveTo(getPoint(i).x, getPoint(i).y);
} else {
polygonPath.lineTo(getPoint(i).x, getPoint(i).y);
}
}
polygonPath.close();
canvas.drawPath(polygonPath, linePaint);
}


绘制连接线

直接连线从圆心到各个顶点

/**
* 绘制连接线
*/
private void drawLines(Canvas canvas) {
for (int i = 0; i < dataCount; i++) {
canvas.drawLine(centerX, centerY, getPoint(i).x, getPoint(i).y, linePaint);
}
}


绘制填充区域

这里的获得百分比坐标的方式可以注意下.

/**
* 绘制填充区域
*/
private void drawRegion(Canvas canvas) {
Path regionPath = new Path();
float percent;
for (int i = 0; i < creditBeans.size(); i++) {
percent = creditBeans.get(i).score * 1.0f / maxScore;
int x = getPoint(i, percent).x;
int y = getPoint(i, percent).y;
if (i == 0) {
regionPath.moveTo(x, y);
} else {
regionPath.lineTo(x, y);
}
}
regionPath.close();
canvas.drawPath(regionPath, regionPaint);
}


绘制总分数

总分数的文字绘制在正中心.

这里要注意文字的宽度和高度的获得方式.

/**
* 绘制总分数
*/
private void drawTotalScore(Canvas canvas) {
int totalScore = 0;
for (CreditBean creditBean : creditBeans) {
totalScore += creditBean.score;
}
//获得文字宽度
float textWidth = totalScorePaint.measureText(String.valueOf(totalScore));
Paint.FontMetrics fontMetrics = totalScorePaint.getFontMetrics();
//获得文字高度
float textHeight = Math.abs(fontMetrics.ascent) - fontMetrics.descent;
canvas.drawText(String.valueOf(totalScore), centerX - textWidth / 2, centerY + textHeight / 2, totalScorePaint);
}


绘制标题和图标

图标和文字位置是根据文字和图标的宽高计算的.

/**
* 绘制标题和图标
*/
private void drawTitleAndIcons(Canvas canvas) {
for (int i = 0; i < creditBeans.size(); i++) {
String title = creditBeans.get(i).title;
int textX = getPoint(i, 1.2f).x;
int textY = getPoint(i, 1.2f).y;

//获得文字的宽高
int textWidth = (int) titlePaint.measureText(title);
Paint.FontMetrics fontMetrics = titlePaint.getFontMetrics();
int textHeight = (int) (Math.abs(fontMetrics.ascent) - fontMetrics.descent);

//获得图标的宽高
Bitmap icon = BitmapFactory.decodeResource(getResources(), creditBeans.get(i).icon);
int iconWidth = icon.getWidth();
int iconHeight = icon.getHeight();
if (i == 0) {
//不需要修正位置
} else if (i == 1) {
textY += textHeight;
} else if (i == 2) {
textX -= textWidth;
textY += textHeight;
} else if (i == 3) {
textX -= textWidth;
} else {
textX -= textWidth / 2;
}
int iconX = textX + textWidth / 2 - iconWidth / 2;
int iconY = textY - textHeight - iconHeight - DensityUtils.dp2px(getContext(), 8);
canvas.drawText(title, textX, textY, titlePaint);
canvas.drawBitmap(icon, iconX, iconY, null);
}
}


3. 设置数据

/**
* 设置数据
*/
public void setData(List<CreditBean> creditBeans, int maxScore) {
this.creditBeans = creditBeans;
this.dataCount = creditBeans.size();
this.maxScore = maxScore;
this.radian = (float) (Math.PI * 2 * 1.0f / dataCount);
}


学到的知识

文字的宽度和高度的获得

//获得文字宽度
float textWidth = totalScorePaint.measureText(String.valueOf(totalScore));
//获得文字高度
Paint.FontMetrics fontMetrics = totalScorePaint.getFontMetrics();
float textHeight = Math.abs(fontMetrics.ascent) - fontMetrics.descent;


获得多边形每个顶点的位置, 坐标的计算是个重点.

注意: Math.sin() 参数是弧度. 如果需要将角度转为弧度, 可以使用Math.toRadian().

计算填充区域顶点坐标和多边形的顶点是在同一条过圆心的直线上. 这里使用了percent来获得两个坐标.

/**
* 获得点坐标
*/
public Point getPoint(int index) {
return getPoint(index, 1);
}

/**
* 获得点坐标,percent为百分比,用于获得填充区域和文字等的坐标位置.
*/
public Point getPoint(int index, float percent) {
int x = 0;
int y = 0;
if (index == 0) {
x = (int) (centerX + radius * Math.sin(radian) * percent);
y = (int) (centerY - radius * Math.cos(radian) * percent);
} else if (index == 1) {
x = (int) (centerX + radius * Math.sin(radian * 1.0f / 2) * percent);
y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent);
} else if (index == 2) {
x = (int) (centerX - radius * Math.sin(radian * 1.0f / 2) * percent);
y = (int) (centerY + radius * Math.cos(radian * 1.0f / 2) * percent);
} else if (index == 3) {
x = (int) (centerX - radius * Math.sin(radian) * percent);
y = (int) (centerY - radius * Math.cos(radian) * percent);
} else if (index == 4) {
x = centerX;
y = (int) (centerY - radius * percent);
}
return new Point(x, y);
}


github地址:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: