因项目需要,需要加入蛛网图的显示,虽然GitHub上早已有很多大神的nb框架,但是还是想自己写写练练手。
项目中显示的蛛网图也比较简单,只需要控制四个进度值,这样就不需要考虑角度旋转的问题了 ,只需要控制上下左右四个进度值得变化就可以了,也就是只取上下左右四个进度值的点就可以了。
首先先获取各个重要点位信息:

@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//初始化各边信息  获取各方向位置点起始位置信息left = leftRightPadding;top = topBottomPadding;right = w - leftRightPadding;bottom = h - topBottomPadding;if (centerPoint == null) {centerPoint = new PointF();}centerPoint.x = w / 2;centerPoint.y = h / 2;progressSpaceX = (centerPoint.x - left)/4;progressSpaceY = (centerPoint.y - top)/4;if (shader == null) {//初始化渐变色背景shader = new LinearGradient(centerPoint.x,top,centerPoint.x,bottom,Color.parseColor("#18C2B1"),Color.parseColor("#FDA23E"), Shader.TileMode.MIRROR);}setProgressValue();}

然后实现蛛网图的刻度效果,主要代码

         //画横竖两条背景线path.moveTo(left,centerPoint.y);path.lineTo(right,centerPoint.y);paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.parseColor("#cccccc"));paint.setStrokeWidth(3);canvas.drawPath(path,paint);path.reset();path.moveTo(centerPoint.x,top);path.lineTo(centerPoint.x,bottom);canvas.drawPath(path,paint);//画蛛网线paint.setShader(shader);paint.setStrokeWidth(3);for (int i = 0; i < 4; i++) {path.reset();path.moveTo(left + progressSpaceX * i,centerPoint.y);path.lineTo(centerPoint.x,top + progressSpaceY * i);path.lineTo(right -  progressSpaceX * i,centerPoint.y);path.lineTo(centerPoint.x,bottom - progressSpaceY * i);path.lineTo(left + progressSpaceX * i,centerPoint.y);canvas.drawPath(path,paint);paint.setStrokeWidth(2);}

然后画个进度标题(示例代码写死,实际应用可自定义标题):

         //画标题paint.setShader(null);paint.setColor(textColor);paint.setStyle(Paint.Style.FILL);paint.setTextSize(textSize);paint.setTextAlign(Paint.Align.CENTER);paint.getTextBounds("节能",0,2,rect);//计算文字高度  左右标题居中显示float de = rect.height();canvas.drawText("节能",centerPoint.x, topBottomPadding /2,paint);canvas.drawText("灾害",centerPoint.x,bottom + topBottomPadding /2,paint);canvas.drawText("卫生",leftRightPadding / 2,centerPoint.y + de/2,paint);canvas.drawText("效能",leftRightPadding / 2 + right,centerPoint.y + de/2,paint);

之后画进度值:

     //画四个方向进度圆点paint.setColor(Color.parseColor("#00BDAA"));paint.setStyle(Paint.Style.FILL);canvas.drawCircle(topPoint.x,topPoint.y,pointCircleRadius,paint);canvas.drawCircle(leftPoint.x,leftPoint.y,pointCircleRadius,paint);canvas.drawCircle(rightPoint.x,rightPoint.y,pointCircleRadius,paint);canvas.drawCircle(bottomPoint.x,bottomPoint.y,pointCircleRadius,paint);//画四个方向进度区域paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5);path.reset();path.moveTo(leftPoint.x,leftPoint.y);path.lineTo(topPoint.x,topPoint.y);path.lineTo(rightPoint.x,rightPoint.y);path.lineTo(bottomPoint.x,bottomPoint.y);path.lineTo(leftPoint.x,leftPoint.y);canvas.drawPath(path,paint);paint.setStyle(Paint.Style.FILL);paint.setColor(Color.parseColor("#b355C7C2"));canvas.drawPath(path,paint);

最后加上动态效果:

 /*** 启动动画* @param topProgress 上方进度值* @param rightProgress 右方进度值* @param bottomProgress 底部进度值* @param leftProgress 左方进度值*/private void startAnimator(final double topProgress,final double rightProgress,final double bottomProgress, final double leftProgress){ValueAnimator topAnimator = ValueAnimator.ofInt(0, 100);topAnimator.setDuration(2000);topAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {Integer v = (Integer) animation.getAnimatedValue();DayHealthProgressView.this.topProgress = v * topProgress/100 ;DayHealthProgressView.this.rightProgress = v* rightProgress/100 ;DayHealthProgressView.this.bottomProgress = v* bottomProgress/100 ;DayHealthProgressView.this.leftProgress = v* leftProgress/100 ;setProgressValue();invalidate();}});topAnimator.start();}

最终效果如下:

完整代码:

package com.zc.tt;import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;import com.blankj.utilcode.util.ConvertUtils;/*** 自定义每日健康蛛网图* @author zc*/
public class DayHealthProgressView extends View {/**画笔*/private Paint paint;private Path path;private Rect rect;/*** 控制四个点信息,中心点、上方进度值点、下方进度值点、左方进度值点、右方进度值点*/private PointF centerPoint,topPoint, bottomPoint,leftPoint,rightPoint;/**蛛网图各方向起始位置*/private float left,right,top,bottom;/**上下间距*/private float topBottomPadding;/**左右间距*/private float leftRightPadding;/**左右进度值单位长度、上下进度值单位长度*/private float progressSpaceX,progressSpaceY;/**背景shader*/private LinearGradient shader;/**字体大小*/private float textSize;/**字体颜色*/private int textColor;/**上方进度值*/private double topProgress;/**下方进度值*/private double bottomProgress;/**左方进度值*/private double leftProgress;/**右方进度值*/private double rightProgress;/**中心店圆的Radius*/private float pointCircleRadius;public DayHealthProgressView(Context context) {super(context);init();}public DayHealthProgressView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);init();}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//初始化各边信息  获取各方向位置点起始位置信息left = leftRightPadding;top = topBottomPadding;right = w - leftRightPadding;bottom = h - topBottomPadding;if (centerPoint == null) {centerPoint = new PointF();}centerPoint.x = w / 2;centerPoint.y = h / 2;progressSpaceX = (centerPoint.x - left)/4;progressSpaceY = (centerPoint.y - top)/4;if (shader == null) {//初始化渐变色背景shader = new LinearGradient(centerPoint.x,top,centerPoint.x,bottom,Color.parseColor("#18C2B1"),Color.parseColor("#FDA23E"), Shader.TileMode.MIRROR);}setProgressValue();}/*** 初始化*/private void init(){if (topPoint == null) {topPoint = new PointF();}if (leftPoint == null) {leftPoint = new PointF();}if (bottomPoint == null) {bottomPoint = new PointF();}if (rightPoint == null) {rightPoint = new PointF();}if (centerPoint == null) {centerPoint = new PointF();}paint = new Paint();path = new Path();paint.setAntiAlias(true);//上下间距和左右间距不一样  左右间距过小会导致文字信息显示不全topBottomPadding = ConvertUtils.dp2px(30);leftRightPadding = ConvertUtils.dp2px(36);textSize = ConvertUtils.sp2px(16);textColor = Color.parseColor("#333333");rect = new Rect();pointCircleRadius = ConvertUtils.dp2px(3);}@Overridepublic void draw(Canvas canvas) {super.draw(canvas);//画横竖两条线path.moveTo(left,centerPoint.y);path.lineTo(right,centerPoint.y);paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.parseColor("#cccccc"));paint.setStrokeWidth(3);canvas.drawPath(path,paint);path.reset();path.moveTo(centerPoint.x,top);path.lineTo(centerPoint.x,bottom);canvas.drawPath(path,paint);//画蛛网线paint.setShader(shader);paint.setStrokeWidth(3);for (int i = 0; i < 4; i++) {path.reset();path.moveTo(left + progressSpaceX * i,centerPoint.y);path.lineTo(centerPoint.x,top + progressSpaceY * i);path.lineTo(right -  progressSpaceX * i,centerPoint.y);path.lineTo(centerPoint.x,bottom - progressSpaceY * i);path.lineTo(left + progressSpaceX * i,centerPoint.y);canvas.drawPath(path,paint);paint.setStrokeWidth(2);}//画标题paint.setShader(null);paint.setColor(textColor);paint.setStyle(Paint.Style.FILL);paint.setTextSize(textSize);paint.setTextAlign(Paint.Align.CENTER);paint.getTextBounds("节能",0,2,rect);//计算文字高度  左右标题居中显示float de = rect.height();canvas.drawText("节能",centerPoint.x, topBottomPadding /2,paint);canvas.drawText("灾害",centerPoint.x,bottom + topBottomPadding /2,paint);canvas.drawText("卫生",leftRightPadding / 2,centerPoint.y + de/2,paint);canvas.drawText("效能",leftRightPadding / 2 + right,centerPoint.y + de/2,paint);//画四个方向进度圆点paint.setColor(Color.parseColor("#00BDAA"));paint.setStyle(Paint.Style.FILL);canvas.drawCircle(topPoint.x,topPoint.y,pointCircleRadius,paint);canvas.drawCircle(leftPoint.x,leftPoint.y,pointCircleRadius,paint);canvas.drawCircle(rightPoint.x,rightPoint.y,pointCircleRadius,paint);canvas.drawCircle(bottomPoint.x,bottomPoint.y,pointCircleRadius,paint);//画四个方向进度区域paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5);path.reset();path.moveTo(leftPoint.x,leftPoint.y);path.lineTo(topPoint.x,topPoint.y);path.lineTo(rightPoint.x,rightPoint.y);path.lineTo(bottomPoint.x,bottomPoint.y);path.lineTo(leftPoint.x,leftPoint.y);canvas.drawPath(path,paint);paint.setStyle(Paint.Style.FILL);paint.setColor(Color.parseColor("#b355C7C2"));canvas.drawPath(path,paint);}/*** 确定进度圆点值*/private void setProgressValue() {if (topPoint == null) {topPoint = new PointF();}if (leftPoint == null) {leftPoint = new PointF();}if (bottomPoint == null) {bottomPoint = new PointF();}if (rightPoint == null) {rightPoint = new PointF();}topPoint.y = (float) (((centerPoint.y - top) * (100 - topProgress)) / 100 + top);topPoint.x = centerPoint.x;bottomPoint.y = (float) ((bottomProgress * (centerPoint.y - topBottomPadding))/100 + centerPoint.y);bottomPoint.x = centerPoint.x;leftPoint.x = (float) (((centerPoint.x - left) * (100 - leftProgress)) / 100 + left);leftPoint.y = centerPoint.y;rightPoint.x = (float) ((rightProgress * (centerPoint.x - leftRightPadding))/100 + centerPoint.x);rightPoint.y = centerPoint.y;}public void setProgress(double topProgress,double rightProgress,double bottomProgress,double leftProgress){startAnimator(topProgress,rightProgress,bottomProgress,leftProgress);}/*** 启动动画* @param topProgress 上方进度值* @param rightProgress 右方进度值* @param bottomProgress 底部进度值* @param leftProgress 左方进度值*/private void startAnimator(final double topProgress,final double rightProgress,final double bottomProgress, final double leftProgress){ValueAnimator topAnimator = ValueAnimator.ofInt(0, 100);topAnimator.setDuration(2000);topAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {Integer v = (Integer) animation.getAnimatedValue();DayHealthProgressView.this.topProgress = v * topProgress/100 ;DayHealthProgressView.this.rightProgress = v* rightProgress/100 ;DayHealthProgressView.this.bottomProgress = v* bottomProgress/100 ;DayHealthProgressView.this.leftProgress = v* leftProgress/100 ;setProgressValue();invalidate();}});topAnimator.start();}public double getTopProgress() {return topProgress;}public void setTopProgress(double topProgress) {this.topProgress = topProgress;setProgressValue();invalidate();}public double getBottomProgress() {return bottomProgress;}public void setBottomProgress(double bottomProgress) {this.bottomProgress = bottomProgress;setProgressValue();invalidate();}public double getLeftProgress() {return leftProgress;}public void setLeftProgress(double leftProgress) {this.leftProgress = leftProgress;setProgressValue();invalidate();}public double getRightProgress() {return rightProgress;}public void setRightProgress(double rightProgress) {this.rightProgress = rightProgress;setProgressValue();invalidate();}public float getPointCircleRadius() {return pointCircleRadius;}public void setPointCircleRadius(float pointCircleRadius) {this.pointCircleRadius = pointCircleRadius;invalidate();}
}

Android初学之自定义简单蛛网(雷达)图相关推荐

  1. android 自定义view: 蛛网/雷达图(三)

    本系列自定义View全部采用kt 系统mac android studio: 4.1.3 kotlin version1.5.0 gradle: gradle-6.5-bin.zip 本篇效果: 蛛网 ...

  2. Android绘图机制 Demo(简单完成美图秀秀的滤镜)

    Android绘图机制 Demo(简单完成美图秀秀的滤镜) 1.xml <?xml version="1.0" encoding="utf-8"?> ...

  3. Android自定义View:雷达图/蜘蛛网图

    运行效果图 雷达图结构分析 对雷达图进行结构拆分,得到一个清晰的思路,这些结构也就是需要绘制的部分.为了能够有更好的扩展性,我将它们作为可定制的属性暴露出来,以下是结构属性表: 结构 相关属性 描述 ...

  4. java 雷达图_Android雷达图(蜘蛛网图),自定义view之雷达图,正五边雷达图,分数图...

    最近业务要做分数雷达图,到网上找了很大,原理都差不多,但是要适用自己的业务,还需要微调.下面是我微调后的效果图 雷达图蜘蛛网.png 原理很简单 1,确定雷达图中心点的坐标 2,用正三角sin,反三角 ...

  5. android 自定义五边形图片,Android自定义View-蜘蛛网属性图(五边形图)

    首先看看效果图: 这里写图片描述 先简要说一下这里需要涉及到的知识点: 高中基本的三角函数 Sin,Cos. 参考的文章: 这里为了尊重上面这篇文章的作者,需要说明一下,下面的代码有部分是参考上面这篇 ...

  6. android 游戏导引(4. 简单纹理贴图)

    这一节主要讲述 opengl 的贴图技术,涉及了简单的纹理知识.临近放年假,忙啊. 源码下载: 点我吧 Table of Contents 1 纹理 Texture 1.1 纹理坐标 和 纹理映射 1 ...

  7. android自定义View: 饼状图绘制(四)

    本系列自定义View全部采用kt 系统mac android studio: 4.1.3 kotlin version1.5.0 gradle: gradle-6.5-bin.zip 本篇效果: 画矩 ...

  8. Android自定义View 多边形能力分析控件,雷达图(蛛网)动态实现

    自定义View实现雷达图还是挺简单的,它能让使用让使用者能一目了然的了解各项指标的变动情形以及好坏趋势.使用得最多的便是Path路径,很适合初学者用来练习. 效果图如下: 下面是实体类的属性: pub ...

  9. android 雷达坐标系,Android Path之绘制雷达图的技巧

    Android Path之绘制雷达图的技巧,绘制蜘蛛网络其实就是绘制指定边数的正多边形,这一步比较简单,比较难的可能就是每个顶点的算法,相关注释我都写了,还有一张来自互联网的图以助于思考,如下: 第一 ...

最新文章

  1. 字符串转 Json 数组
  2. python 画蝴蝶_ProE常用曲线方程:Python Matplotlib 版本代码(蝴蝶曲线)
  3. java 读取html模板文件_Java根据html模板创建 html文件
  4. 步进电机的单双极驱动
  5. 【OpenCV入门学习笔记1】:Mat对象的指针操作和掩膜操作
  6. 【Xamarin 挖墙脚系列:Xamarin SDK开源了................】
  7. 求职及学习心情文章收集
  8. 什么是计算机嵌套分类汇总,excel嵌套分类汇总 Excel表格中创建嵌套分类汇总和查看嵌套分类汇总明细的方法...
  9. idea 代码格式化 无效
  10. 黑苹果hackintosh wifi驱动安装
  11. 我是怎样开发一个开源系统的安全模块?
  12. boss网人脸识别认证_在手机上怎样进行社保人脸识别认证
  13. 如何快速给图片加水印?
  14. 企企通持续助力全球管道预制先行者「迈科管道」,二期项目逐步启动
  15. 转:(记录)C语言中的itoa()函数的用法解析
  16. shell学习-基础篇
  17. 计算机网络工程小型校园网搭建,(毕业论文)中小型校园网络组建方案设计.doc
  18. R语言统计分析微生物组数据(第三章3)
  19. L2-030 冰岛人(并查集)
  20. Security onion 开源IDS入侵检测系统 2.3.220超详细保姆级部署教程

热门文章

  1. 工行nc银企互联java代码_C#工行 银企互联demo(NC)
  2. winds开放指定端口
  3. 山东省省内院校毕业生注册【山东省高校毕业生就业信息网】须知
  4. 用Python代码画一个足球(附完整代码)
  5. Eclipse安装JDK11方式
  6. buuctf——rot
  7. 微积分 | 函数连续与间断点
  8. 【Mac】anaconda创建虚拟环境+jupyter虚拟环境配置
  9. C# webBrowser 通过代理访问网页
  10. Tensorflow神经网络预测股票均价