Android-自定义能力分布图

xiaoxiao2021-02-28  14

一、上图镇楼:

在医生的微信群里面看到医生发的能力分布图,想实现一下,于是花了两个小时写了出来,由于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; //View宽度 private int viewWidth; //View高度 private int viewHeight; //中心x坐标 private int centerX; //中心Y坐标 private int centerY; //padding值 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));//设置虚线15sp实线,15sp虚线 int angle = 360 / abilityNumber;//两种能力虚线之间的夹角 float X1;//能力虚线在大圆上的X坐标 float Y1;//能力虚线在大圆上的Y坐标 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

转载请注明原文地址: https://www.6miu.com/read-200404.html

最新回复(0)