一、上图镇楼:
在医生的微信群里面看到医生发的能力分布图,想实现一下,于是花了两个小时写了出来,由于gif录制原因,所以棱角效果不明显,请自行运行至手机查看实际效果。话不多说,上源码。
二、源代码
package com.lxh.custom.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
* Created by lxh on 2017/7/14.
* QQ-632671653
*/
public class AbilityMapView extends View {
private int LAYER =
3;
private String[] ability;
private int[] abilityScore;
private int abilityFullMark =
100;
private int viewWidth;
private int viewHeight;
private int centerX;
private int centerY;
private int padding;
private int Radius;
private int[] colors = {Color.BLUE,Color.BLACK,Color.CYAN,Color.GREEN,Color.MAGENTA};
private Context context;
public AbilityMapView(Context context) {
super(context);
this.context = context;
}
public AbilityMapView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
@Override
protected void onMeasure(
int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = MeasureSpec.getSize(widthMeasureSpec);
viewHeight = MeasureSpec.getSize(heightMeasureSpec);
padding = dip2px(
70);
if (viewWidth<viewHeight){
viewHeight = viewWidth;
}
else {
viewWidth = viewHeight;
}
setMeasuredDimension(viewWidth,viewHeight);
centerX = viewWidth /
2;
centerY = viewWidth /
2;
Radius = viewWidth /
2 - padding;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint =
new Paint();
drawLayer(canvas,paint,LAYER);
if (ability.length>
0){
drawAbilityLine(canvas,paint,ability.length);
if (ability.length != colors.length){
Log.e(
"AbilityMapView",
"色值数量与能力数量不匹配!");
return;
}
if (ability.length != abilityScore.length){
Log.e(
"AbilityMapView",
"分数值数量与能力数量不匹配!");
return;
}
drawAbilityMap(canvas,paint);
}
}
/**
* 绘制文字
* @param canvas
* @param x
* @param y
* @param text
* @param color
* @param paint
*/
private void drawText(Canvas canvas,
float x,
float y,String text,
int color,Paint paint){
paint.reset();
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(
true);
paint.setColor(color);
canvas.drawCircle(x,y,dip2px(
3),paint);
paint.setTextSize(dip2px(
10));
Rect rect =
new Rect();
paint.getTextBounds(text,
0, text.length(), rect);
int w = rect.width();
int h = rect.height();
float textX =
0;
float textY =
0;
if (x>=centerX&&y<centerY){
textX = x+dip2px(
5);
textY = y;
}
if (x>=centerX&&y>=centerY){
textX = x;
textY = y+h+dip2px(
5);
}
if (x<centerX&&y>centerY){
textX = x-w-dip2px(
5);
textY = y+h+dip2px(
5);
}
if (x<centerX&&y<=centerY){
textX = x-w-dip2px(
5);
textY = y-h;
}
canvas.drawText(text,textX,textY,paint);
}
/**
* 绘制能力分布
* @param canvas
* @param paint
*/
private void drawAbilityMap(Canvas canvas,Paint paint){
int angle =
360 / ability.length;
paint.setColor(Color.parseColor(
"#FF435AD7"));
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(
true);
for (
int i =
0;i<ability.length;i++){
Path path =
new Path();
path.moveTo(centerX,centerY);
float radius = (abilityScore[i]*Radius)/abilityFullMark;
float tempX = (
float) (centerX + radius * Math.cos(
2 * Math.PI * (-
90+angle*i) /
360));
float tempY = (
float) (centerY + radius * Math.sin(
2 * Math.PI * (-
90+angle*i) /
360));
path.lineTo(tempX,tempY);
int index = i+
1;
if (index>=abilityScore.length){
index =
0;
}
float endRadius = (abilityScore[index]*Radius)/abilityFullMark;
float endX = (
float) (centerX + endRadius * Math.cos(
2 * Math.PI * (-
90+angle*(index)) /
360));
float endY = (
float) (centerY + endRadius * Math.sin(
2 * Math.PI * (-
90+angle*(index)) /
360));
LinearGradient lg=
new LinearGradient(tempX,tempY,endX,endY,Color.parseColor(
"#FFDF9C28"),
Color.parseColor(
"#FFECBB67"), Shader.TileMode.MIRROR);
paint.setShader(lg);
path.lineTo(endX,endY);
path.close();
canvas.drawPath(path,paint);
float flagX = (
float) (centerX + (Radius+
30) * Math.cos(
2 * Math.PI * (-
90+angle*(i)) /
360));
float flagY = (
float) (centerY + (Radius+
30) * Math.sin(
2 * Math.PI * (-
90+angle*(i)) /
360));
drawText(canvas,flagX,flagY,ability[i]+
" "+abilityScore[i],colors[i],paint);
}
}
/**
* 绘制层级圆
* @param canvas
* @param paint
* @param layer
*/
private void drawLayer(Canvas canvas, Paint paint,
int layer){
int radius;
paint.setColor(Color.parseColor(
"#FFcccccc"));
paint.setStrokeWidth(dip2px(
1));
paint.setAntiAlias(
true);
paint.setStyle(Paint.Style.STROKE);
for(
int i =
1;i<=layer;i++){
radius = (Radius/layer)*i;
canvas.drawCircle(centerX,centerY,radius,paint);
}
}
/**
* 绘制能力虚线
* @param canvas
* @param paint
* @param abilityNumber
*/
private void drawAbilityLine(Canvas canvas,Paint paint,
int abilityNumber){
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(
2);
paint.setColor(Color.parseColor(
"#FFcccccc"));
paint.setAntiAlias(
true);
paint.setPathEffect(
new DashPathEffect(
new float[] {
15,
15},
0));
int angle =
360 / abilityNumber;
float X1;
float Y1;
for(
int i =
0;i<abilityNumber;i++){
X1 = (
float) (centerX + Radius * Math.cos(
2 * Math.PI * (-
90+angle*i) /
360));
Y1 = (
float) (centerY + Radius * Math.sin(
2 * Math.PI * (-
90+angle*i) /
360));
Path mPath =
new Path();
mPath.reset();
mPath.moveTo(centerX, centerY);
mPath.lineTo(X1, Y1);
canvas.drawPath(mPath, paint);
}
}
public void setLayer(
int layer){
this.LAYER = layer;
postInvalidate();
}
public void setAbility(String[] ability) {
this.ability = ability;
postInvalidate();
}
public void setAbilityScore(
int[] abilityScore) {
this.abilityScore = abilityScore;
postInvalidate();
}
public void setAbilityFullMark(
int abilityFullMark) {
this.abilityFullMark = abilityFullMark;
postInvalidate();
}
public void setColors(
int[] colors) {
this.colors = colors;
postInvalidate();
}
/**
* 将dip或dp值转换为px值,保证尺寸大小不变
*
* @param dipValue
* (DisplayMetrics类中属性density)
* @return
*/
public int dip2px(
float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (
int) (dipValue * scale +
0.5f);
}
}
在XML中使用
<
com.lxh.custom.view.AbilityMapView
android:id=
"@+id/abilityView"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content" />
在Activity中进行初始化
s = new int[]{
90,
50,
60,
40,
35}
colors = new int[]{Color
.BLUE, Color
.BLACK, Color
.CYAN, Color
.GREEN, Color
.MAGENTA}
abilityMapView = (AbilityMapView) findViewById(R
.id.abilityView)
String [] t = {
"攻击",
"防御",
"生存",
"控制",
"辅助"}
abilityMapView
.setAbility(t)
abilityMapView
.setAbilityScore(s)
abilityMapView
.setAbilityFullMark(
100)
abilityMapView
.setLayer(
3)
abilityMapView
.setColors(colors)
代码不复杂,而且都带有注释,项目完整地址:https://github.com/lxh632671653/custom 技术交流请加QQ:632671653