package com.wangs.sesamecreditscore
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Point
import android.support.annotation.Nullable
import android.util.AttributeSet
import android.view.View
/**
* 芝麻信用分
* Created by wangs on 2017/6/24.
*/
public class CreditScoreView extends View {
//数据个数
private int dataCount = 5
//每个角的弧度
private float radian = (float) (Math.PI * 2 / dataCount)
//雷达图半径
private float radius
//中心X坐标
private int centerX
//中心Y坐标
private int centerY
//各维度标题
private String[] titles = {"履约能力", "信用历史", "人脉关系", "行为偏好", "身份特质"}
//各维度图标
private int[] icons = {R.drawable.ic_performance, R.drawable.ic_history, R.drawable.ic_contacts,
R.drawable.ic_predilection, R.drawable.ic_identity}
//各维度分值
private float[] data = {130, 150, 160, 120, 150}
//数据最大值
private float maxValue = 190
//雷达图与标题的间距
private int radarMargin = DpUtils.dpToPx(getContext(), 15)
//DensityUtils.dp2px(getContext(), 15)
//雷达区画笔
private Paint mainPaint
//数据区画笔
private Paint valuePaint
//分数画笔
private Paint scorePaint
//标题画笔
private Paint titlePaint
//图标画笔
private Paint iconPaint
//分数大小
private int scoreSize = DpUtils.dpToPx(getContext(), 28)
//标题文字大小
private int titleSize = DpUtils.dpToPx(getContext(), 13)
public CreditScoreView(Context context) {
this(context, null)
}
public CreditScoreView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0)
}
public CreditScoreView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr)
init()
}
private void init() {
mainPaint = new Paint()
mainPaint.setColor(Color.WHITE)
mainPaint.setAntiAlias(true)
mainPaint.setStrokeWidth(0.3f)
mainPaint.setStyle(Paint.Style.STROKE)
valuePaint = new Paint()
valuePaint.setAntiAlias(true)
valuePaint.setColor(Color.WHITE)
valuePaint.setAlpha(120)
valuePaint.setStyle(Paint.Style.FILL_AND_STROKE)
scorePaint = new Paint()
scorePaint.setAntiAlias(true)
scorePaint.setColor(Color.WHITE)
scorePaint.setTextSize(scoreSize)
scorePaint.setStyle(Paint.Style.FILL)
scorePaint.setTextAlign(Paint.Align.CENTER)
titlePaint = new Paint()
titlePaint.setAntiAlias(true)
titlePaint.setTextSize(titleSize)
titlePaint.setColor(Color.WHITE)
titlePaint.setStyle(Paint.Style.FILL)
iconPaint = new Paint()
iconPaint.setAntiAlias(true)
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh)
//雷达图半径(取宽或高的最小值的1/4作为半径画圆)
radius = Math.min(w, h) / 2 * 0.5f
centerX = w / 2
centerY = h / 2
postInvalidate()
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas)
drawPolygon(canvas)
drawLine(canvas)
drawRegion(canvas)
drawScore(canvas)
drawTitle(canvas)
drawableIcon(canvas)
}
/**
* 绘制多边形
*/
private void drawPolygon(Canvas canvas) {
Path path = new Path()
for (int i = 0
if (i == 0) {
path.moveTo(getPoint(i).x, getPoint(i).y)
} else if (i > 0) {
path.lineTo(getPoint(i).x, getPoint(i).y)
}
}
path.close()
canvas.drawPath(path, mainPaint)
}
/**
* 绘制中心点的连接线
*/
private void drawLine(Canvas canvas) {
Path path = new Path()
for (int i = 0
path.reset()
path.moveTo(centerX, centerY)
path.lineTo(getPoint(i).x, getPoint(i).y)
canvas.drawPath(path, mainPaint)
}
}
/**
* 绘制覆盖图
*/
private void drawRegion(Canvas canvas) {
Path path = new Path()
for (int i = 0
//计算百分比
float percentage = data[i] / maxValue
float x = getPoint(i, 0, percentage).x
float y = getPoint(i, 0, percentage).y
if (i == 0) {
path.moveTo(x, y)
} else if (i > 0) {
path.lineTo(x, y)
}
}
//绘制填充区域的边界
path.close()
valuePaint.setStyle(Paint.Style.STROKE)
canvas.drawPath(path, valuePaint)
//绘制填充区域的填充物
valuePaint.setStyle(Paint.Style.FILL_AND_STROKE)
canvas.drawPath(path, valuePaint)
}
/**
* 绘制分数
*/
private void drawScore(Canvas canvas) {
int score = 0
for (int i = 0
score += data[i]
}
canvas.drawText(String.valueOf(score), centerX, centerY + scoreSize / 2, scorePaint)
}
/**
* 绘制title
*/
private void drawTitle(Canvas canvas) {
for (int i = 0
//获取点坐标
float x = getPoint(i, radarMargin, 1).x
float y = getPoint(i, radarMargin, 1).y
String title = titles[i]
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), icons[i])
int iconHeight = bitmap.getHeight()
float titleWidth = titlePaint.measureText(titles[i])
//底下两个角的坐标需要向下移动半个图片的位置(1、2)
if (i == 1) {
y = y + iconHeight / 2
} else if (i == 2) {
y = y + iconHeight / 2
x = x - titleWidth
} else if (i == 3) {
x = x - titleWidth
} else if (i == 4) {
x = x - titleWidth / 2
}
canvas.drawText(titles[i],x,y,titlePaint)
}
}
/**
* 绘制图标
*/
private void drawableIcon(Canvas canvas){
for (int i = 0
float x = getPoint(i,radarMargin,1).x
float y = getPoint(i,radarMargin,1).y
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),icons[i])
float iconWidth = bitmap.getWidth()
float iconHeight = bitmap.getHeight()
float titleHeight = getTextHeight(titlePaint)
float titleWidth = titlePaint.measureText(titles[i])
//上面获取到的x、y坐标是标题左下角的坐标
//需要将图标移动到标题上方居中位置
if(i == 0){
x += (titleWidth-iconWidth)/2
y -= (titleHeight+iconHeight)
}else if(i == 1){
x += (titleWidth-iconWidth)/2
y -= titleHeight + iconHeight/2
}else if(i == 2){
x -= titleWidth+ (titleWidth - iconWidth)/2
y -= titleHeight+iconHeight/2
}else if(i == 3){
x -= titleWidth + (titleWidth - iconWidth)/2
y -= (titleHeight+iconHeight)
}else if(i == 4){
x -= titleWidth/2
y -= titleHeight + iconHeight
}
canvas.drawBitmap(bitmap,x,y,titlePaint)
}
}
/**
* 获取文本的高度
*
* @param paint 文本绘制的画笔
* @return 文本高度
*/
private int getTextHeight(Paint paint) {
Paint.FontMetrics fontMetrics = paint.getFontMetrics()
return (int) (fontMetrics.descent - fontMetrics.ascent)
}
/**
* 获取雷达图上各个点的坐标
*
* @param position 坐标位置(右上角为0,顺时针递增)
* @return 坐标
*/
private Point getPoint(int position) {
return getPoint(position, 0, 1)
}
/**
* 获取雷达图上各个点的坐标(包括维度标题与图标的坐标)
* 需要计算正弦和余弦
*
* @param position 坐标位置
* @param radarMargin 雷达图与维度标题的间距
* @param percent 覆盖区的的百分比
* @return 坐标
*/
private Point getPoint(int position, int radarMargin, float percent) {
int x = 0
int y = 0
if (position == 0) {
x = (int) (centerX + (radius + radarMargin) * Math.sin(radian) * percent)
y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent)
} else if (position == 1) {
x = (int) (centerX + (radius + radarMargin) * Math.sin(radian / 2) * percent)
y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent)
} else if (position == 2) {
x = (int) (centerX - (radius + radarMargin) * Math.sin(radian / 2) * percent)
y = (int) (centerY + (radius + radarMargin) * Math.cos(radian / 2) * percent)
} else if (position == 3) {
x = (int) (centerX - (radius + radarMargin) * Math.sin(radian) * percent)
y = (int) (centerY - (radius + radarMargin) * Math.cos(radian) * percent)
} else if (position == 4) {
x = centerX
y = (int) (centerY - (radius + radarMargin) * percent)
}
return new Point(x, y)
}
}
package com.wangs.sesamecreditscore;
import android.content.Context;
public class DpUtils {
public static int dpToPx(Context context, float value){
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (value * scale + 0.5f);
}
public static int pxToDp(Context context, float value){
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (value / scale + 0.5f);
}
}