自定义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

相关文章

Python在二进制文件中进行数据搜索的实战指南

《Python在二进制文件中进行数据搜索的实战指南》在二进制文件中搜索特定数据是编程中常见的任务,尤其在日志分析、程序调试和二进制数据处理中尤为重要,下面我们就来看看如何使用Python实现这一功能吧... 目录简介1. 二进制文件搜索概述2. python二进制模式文件读取(rb)2.1 二进制模式与文本

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

Java中Map的五种遍历方式实现与对比

《Java中Map的五种遍历方式实现与对比》其实Map遍历藏着多种玩法,有的优雅简洁,有的性能拉满,今天咱们盘一盘这些进阶偏基础的遍历方式,告别重复又臃肿的代码,感兴趣的小伙伴可以了解下... 目录一、先搞懂:Map遍历的核心目标二、几种遍历方式的对比1. 传统EntrySet遍历(最通用)2. Lambd

Django调用外部Python程序的完整项目实战

《Django调用外部Python程序的完整项目实战》Django是一个强大的PythonWeb框架,它的设计理念简洁优雅,:本文主要介绍Django调用外部Python程序的完整项目实战,文中通... 目录一、为什么 Django 需要调用外部 python 程序二、三种常见的调用方式方式 1:直接 im

springboot+redis实现订单过期(超时取消)功能的方法详解

《springboot+redis实现订单过期(超时取消)功能的方法详解》在SpringBoot中使用Redis实现订单过期(超时取消)功能,有多种成熟方案,本文为大家整理了几个详细方法,文中的示例代... 目录一、Redis键过期回调方案(推荐)1. 配置Redis监听器2. 监听键过期事件3. Redi

SpringBoot全局异常拦截与自定义错误页面实现过程解读

《SpringBoot全局异常拦截与自定义错误页面实现过程解读》本文介绍了SpringBoot中全局异常拦截与自定义错误页面的实现方法,包括异常的分类、SpringBoot默认异常处理机制、全局异常拦... 目录一、引言二、Spring Boot异常处理基础2.1 异常的分类2.2 Spring Boot默

基于SpringBoot实现分布式锁的三种方法

《基于SpringBoot实现分布式锁的三种方法》这篇文章主要为大家详细介绍了基于SpringBoot实现分布式锁的三种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、基于Redis原生命令实现分布式锁1. 基础版Redis分布式锁2. 可重入锁实现二、使用Redisso

SpringBoo WebFlux+MongoDB实现非阻塞API过程

《SpringBooWebFlux+MongoDB实现非阻塞API过程》本文介绍了如何使用SpringBootWebFlux和MongoDB实现非阻塞API,通过响应式编程提高系统的吞吐量和响应性能... 目录一、引言二、响应式编程基础2.1 响应式编程概念2.2 响应式编程的优势2.3 响应式编程相关技术

C#实现将XML数据自动化地写入Excel文件

《C#实现将XML数据自动化地写入Excel文件》在现代企业级应用中,数据处理与报表生成是核心环节,本文将深入探讨如何利用C#和一款优秀的库,将XML数据自动化地写入Excel文件,有需要的小伙伴可以... 目录理解XML数据结构与Excel的对应关系引入高效工具:使用Spire.XLS for .NETC

自定义注解SpringBoot防重复提交AOP方法详解

《自定义注解SpringBoot防重复提交AOP方法详解》该文章描述了一个防止重复提交的流程,通过HttpServletRequest对象获取请求信息,生成唯一标识,使用Redis分布式锁判断请求是否... 目录防重复提交流程引入依赖properties配置自定义注解切面Redis工具类controller