自定义View实战之饼状图效果实现

2023-10-08 12:38

本文主要是介绍自定义View实战之饼状图效果实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

效果图预览
这里写图片描述

1. 分析

1. 饼状图这个首先需要确定几块饼,确定每一块饼需要绘制的角度
2. 根据饼的范围计算百分比的坐标位置
3. 动画处理
4. 中间白色圆和文字的绘制

2. 实现原理

1. 绘制各个饼,可以有两种实现方式 一种通过canvas.drawArc然后中间部分用白色圆给盖住,
另一种方式是Path.arcTo然后用path.op方法取交集
2. 绘制中间文字和白色的圆 通过canvas.drawCircle和canvas.drawText
3.动画处理 计算每一个饼扫描过的角度 计算每一块绘制的角度

3. 初始化一些东西 初始化一般我放在onSizeChanged方法中

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mCenterX = w / 2;mCenterY = h / 2;mInRadius = dp2px(60);mOutRadius = dp2px(120);// setProgressAnimation(DURATION);
}

4. 绘制中间白色圆和中心文字

//画中间白色的圆
private void drawWhiteCircle(Canvas canvas) {canvas.drawCircle(0,0,mInRadius,mWhiteCirclePaint);
}//画中间饼状图文字
private void drawText(Canvas canvas) {String text = "饼状图";//设置文字水平居中mTextPaint.setTextAlign(Paint.Align.CENTER);//测量文字的宽高 要使文字竖直方向也居中mTextPaint.getTextBounds(text,0,text.length(), mTextRect);int height = mTextRect.height();canvas.drawText(text,0,0+height / 2,mTextPaint);
}

5. 画饼状扇形图 这里我为了简单平分了5份饼

  1. canvas.save()和canvas.restore()是为了保证当前画布操作不会影响之前或者之后的操作,需要注意的是一般是存对出现,不然可能会抛异常
  2. mPieChartNum:你要等分的饼的数量 这里我就为了简单等分了5份
  3. mDrawAngle:每一个饼状图扫描的角度 比如均分5个饼的话 mDrawAngle = 360 / 5 = 72度
  4. //分别是计算x,y方向的坐标值
    mOutRadius*(float) Math.cos(Math.toRadians(mStartAngle))
    mOutRadius*(float) Math.sin(Math.toRadians(mStartAngle))
    mOutPath.arcTo 添加圆环
  5. 取圆和圆环的交集
    // op(a,b,Path.Op.REVERSE_DIFFERENCE) b-a的交集
    mPath.op(mInPath,mOutPath, Path.Op.REVERSE_DIFFERENCE)
//画饼状扇形
private void drawPieChart(Canvas canvas) {canvas.save();mInPath.reset();mOutRectF.set(-mOutRadius, -mOutRadius, mOutRadius, mOutRadius);mInPath.addCircle(0,0,mInRadius, Path.Direction.CW);for (int i = 0; i < mPieChartNum; i++) {mStartAngle = (i == 0) ? 0 : mStartAngle + mScaleAngle;if (Math.min(mDrawAngle, mAnimatedValue - mStartAngle) >= 0) {float drawAngle = Math.min(mDrawAngle, mAnimatedValue - mStartAngle);mOutPaint.setColor(mColors[i]);mOutPath.lineTo(mOutRadius*(float) Math.cos(Math.toRadians(mStartAngle)),mOutRadius*(float) Math.sin(Math.toRadians(mStartAngle)));mOutPath.arcTo(mOutRectF, mStartAngle, drawAngle);// op(a,b,Path.Op.REVERSE_DIFFERENCE)  b-a的交集mPath.op(mInPath,mOutPath, Path.Op.REVERSE_DIFFERENCE);canvas.drawPath(mPath,mOutPaint);//画透明度圆环drawInRing(canvas,mStartAngle,drawAngle);//画完一段圆弧再画百分比文字if(drawAngle % mDrawAngle== 0) {drawPercentText(canvas, mStartAngle);}}mPath.reset();mOutPath.reset();}canvas.restore();
}//画百分比文字
private void drawPercentText(Canvas canvas,float startAngle) {float angle = mDrawAngle / 2 + startAngle;//计算x,y的时候其实并不需要在不同象限单独计算  比如说 cos0 = 1  -cos(180-180) = cos 180 = -1float x = (float) (0.75 * mOutRadius * Math.cos(Math.toRadians(angle))) ;float y = (float) (0.75 * mOutRadius * Math.sin(Math.toRadians(angle))) ;DecimalFormat df = new DecimalFormat("0");String format = df.format(100 * 1.0f / mPieChartNum) + "%";mTextPaint.getTextBounds(format,0,format.length(),mPercentRect);canvas.drawText(format,x,y + mPercentRect.height() / 2,mTextPaint);
}

6. 动画处理

//设置进度条动画
public void setProgressAnimation(long duration) {if(mProgressAnimator != null && mProgressAnimator.isRunning()){mProgressAnimator.cancel();mProgressAnimator.start();}else {mProgressAnimator = ValueAnimator.ofFloat(0, 360).setDuration(duration);mProgressAnimator.setInterpolator(new AccelerateInterpolator());mProgressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {/**每次要绘制的圆弧角度**/mAnimatedValue = (float) animation.getAnimatedValue();invalidate();}});mProgressAnimator.start();}
}

7. 项目源代码下载

后面统一提供代码下载地址

8. 联系方式

QQ:1509815887

这篇关于自定义View实战之饼状图效果实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/165325

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Python版本信息获取方法详解与实战

《Python版本信息获取方法详解与实战》在Python开发中,获取Python版本号是调试、兼容性检查和版本控制的重要基础操作,本文详细介绍了如何使用sys和platform模块获取Python的主... 目录1. python版本号获取基础2. 使用sys模块获取版本信息2.1 sys模块概述2.1.1

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

通过React实现页面的无限滚动效果

《通过React实现页面的无限滚动效果》今天我们来聊聊无限滚动这个现代Web开发中不可或缺的技术,无论你是刷微博、逛知乎还是看脚本,无限滚动都已经渗透到我们日常的浏览体验中,那么,如何优雅地实现它呢?... 目录1. 早期的解决方案2. 交叉观察者:IntersectionObserver2.1 Inter