自定义雷达图 根据项目需求在图中画多条线
/**
* 自定义多边形统计
*
* @author roc
*/
public class PolygonCustomeView extends View {
int width, height;
// 最大半径
float maxRadius;
// 外层点位置
List<Point> maxPointList;
// 边数
int sideCount;
// 角度
float angle;
// 层数
int loopCount;
// 绘制边的Paint
private Paint sidePaint;
// 绘制内容的Paint
private Paint areaPaint;
// 绘制文字的Paint
private Paint textPaint;
// private List<Float> pointValue;
private List<List<Float>> pointValue;
private List<String> pointName;
public PolygonCustomeView(Context context) {
super(context);
}
public PolygonCustomeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public PolygonCustomeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
initPaint();
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.Polygon);
// 设置文字颜色
setTextColor(typedArray.getColor(R.styleable.Polygon_ptitleColor, Color.BLACK));
// 设置文字大小
setTextSize(typedArray.getInteger(R.styleable.Polygon_titleSize, 15));
// 设置绘制数据线的颜色
// setAreaColor(typedArray.getColor(R.styleable.Polygon_areaColor,
// Color.BLACK));
// 设置边颜色
// setSideColor(typedArray.getColor(R.styleable.Polygon_sideColor,
// Color.BLACK));
// 设置层数
setLoopCount(typedArray.getInteger(R.styleable.Polygon_loopCount, 0));
// 设置边数
// setSideCount(typedArray.getInteger(R.styleable.Polygon_sideCount,
// 0));
typedArray.recycle();
}
private void initPaint() {
sidePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
areaPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
sidePaint.setStyle(Paint.Style.STROKE);
areaPaint.setStyle(Paint.Style.STROKE);
areaPaint.setStrokeWidth(3);
textPaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!canDraw()) {
return;
} else {
canvas.translate(width / 2, height / 2);
computeMaxPoint();
drawPolygon(canvas);
drawLine(canvas);
drawArea(canvas);
drawText(canvas);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
maxRadius = (float) ((height / 2) * 0.8);
postInvalidate();
}
/**
* 获取外层点坐标
*/
public void computeMaxPoint() {
maxPointList = new ArrayList<>();
for (int i = 0; i < sideCount; i++) {
// 按照android的坐标系,如果不减去90度直接乘上cos的话,第一个顶点会默认在中心的右侧,
// 而一般的认知是第一个点在正上方,所以减去90度
float currentAngle = i * angle - 90;
if (sideCount < 3)
currentAngle = i * angle - 120;
float currentX = (float) (maxRadius * Math.cos((currentAngle / 180) * Math.PI));
float currentY = (float) (maxRadius * Math.sin((currentAngle / 180) * Math.PI));
Point point = new Point();
point.setX(currentX);
point.setY(currentY);
maxPointList.add(point);
}
}
/**
* 绘制多边形的每一层
*
* @param canvas
*/
private void drawPolygon(Canvas canvas) {
Path path = new Path();
for (int i = loopCount; i > 0; i--) {
if (i == loopCount) {
if (pointName == null || pointName.size() == 0) {
sidePaint.setStyle(Paint.Style.STROKE);
sidePaint.setColor(Color.parseColor("#9f9f9f"));
} else {
sidePaint.setStyle(Paint.Style.FILL);
sidePaint.setColor(Color.parseColor("#e5e5e5"));
}
} else {
sidePaint.setStyle(Paint.Style.STROKE);
sidePaint.setColor(Color.parseColor("#aeaeae"));
}
path.reset();
float rate = computeRate(i, loopCount);
for (int j = 0; j < sideCount; j++) {
float currentX = maxPointList.get(j).getX() * rate;
float currentY = maxPointList.get(j).getY() * rate;
// 如果是第一个点,移动到该位置
if (j == 0) {
path.moveTo(currentX, currentY);
} else {// 否则连接上一个点
path.lineTo(currentX, currentY);
}
}
path.close();
canvas.drawPath(path, sidePaint);
}
}
/**
* 跟具层数判断位于最大半径的位置
*
* @param value
* 第几层
* @param max
* 最大层数
* @return
*/
private float computeRate(float value, float max) {
return value / max;
}
/*
* 画出从中心向各顶点的连线
*/
private void drawLine(Canvas canvas) {
Path path = new Path();
for (int i = 0; i < sideCount; i++) {
path.reset();
path.lineTo(maxPointList.get(i).getX(), maxPointList.get(i).getY());
canvas.drawPath(path, sidePaint);
}
}
/**
* 绘制传入的数值对应的覆盖区域
*
* @param canvas
*/
private void drawArea(Canvas canvas) {
if (pointValue == null || pointValue.size() == 0)
return;
Path path = new Path();
for (int i = 0; i < pointValue.size(); i++) {
if (i == 0) {
areaPaint.setColor(Color.parseColor("#30b4b8"));
} else if (i == 1) {
areaPaint.setColor(Color.parseColor("#60b32f"));
} else if (i == 2) {
areaPaint.setColor(Color.parseColor("#ef2a34"));
}
path.reset();
// 如果小于三条边 就从中心点开始连线
if (sideCount < 3) {
for (int j = 0; j < sideCount; j++) {
float rate = pointValue.get(i).get(j);
float currentX = maxPointList.get(j).getX() * rate;
float currentY = maxPointList.get(j).getY() * rate;
path.moveTo(0, 0);
path.lineTo(currentX, currentY);
}
} else {// 否则连接各个科目成绩点
for (int j = 0; j < sideCount; j++) {
float rate = pointValue.get(i).get(j);
float currentX = maxPointList.get(j).getX() * rate;
float currentY = maxPointList.get(j).getY() * rate;
if (j == 0) {
// 如果是第一个点,移动到该位置
path.moveTo(currentX, currentY);
} else {
// 否则连接这个点和上一个点
path.lineTo(currentX, currentY);
}
}
}
path.close();
canvas.drawPath(path, areaPaint);
}
}
/**
* 绘制文字
*
* @param canvas
*/
private void drawText(Canvas canvas) {
if (pointName == null || pointName.size() == 0) {
return;
}
for (int i = 0; i < pointName.size(); i++) {
float currentAngle = i * angle;
if (currentAngle < 180) {
float currentX = maxPointList.get(i).getX() * 1.1f;
float currentY = maxPointList.get(i).getY() * 1.1f;
canvas.drawText(pointName.get(i),
currentX - (textPaint.getTextSize() / 4) * (pointName.get(i).length()), currentY, textPaint);
} else {// 如果大于180度 就让文字靠左
float currentX = maxPointList.get(i).getX() * 1.2f;
float currentY = maxPointList.get(i).getY() * 1.2f;
canvas.drawText(pointName.get(i),
currentX - (textPaint.getTextSize() / 4) * (pointName.get(i).length()), currentY, textPaint);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
/**
* 判断是否可以绘制 层数大于0,各边上的数值不能为null
*
* @return
*/
private boolean canDraw() {
if (loopCount <= 0) {
return false;
}
return true;
}
public void setTextColor(int color) {
textPaint.setColor(color);
}
public void setTextSize(int size) {
textPaint.setTextSize(dpToPixel(size));
}
public void setAreaColor(int color) {
areaPaint.setColor(color);
areaPaint.setAlpha(150);
}
public void setSideColor(int color) {
sidePaint.setColor(color);
}
public void setLoopCount(int loopCount) {
this.loopCount = loopCount;
}
public void setSideCount(int sideCount) {
if (sideCount <= 0)
sideCount = 7;
this.sideCount = sideCount;
angle = 360 / sideCount;
}
public void setPointValue(List<List<Float>> pointValue) {
this.pointValue = pointValue;
}
public void setPointName(List<String> pointName) {
this.pointName = pointName;
}
public int getsideCount() {
return sideCount;
}
public int getLoopCount() {
return loopCount;
}
public List<List<Float>> getPointValue() {
return pointValue;
}
public List<String> getPointName() {
return pointName;
}
public static float dpToPixel(float dp) {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
return dp * metrics.density;
}
}
attrs文件
<!-- 多边形 -->
<declare-styleable name="Polygon">
<attr name="ptitleColor" format="integer" />
<attr name="titleSize" format="integer" />
<attr name="sideCount" format="integer" />
<attr name="loopCount" format="integer" />
</declare-styleable>
Point类
public class Point {
private float x;
private float y;
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
", y=" + y +
'}';
}
}
网友评论