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

相关文章

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

Go语言使用sync.Mutex实现资源加锁

《Go语言使用sync.Mutex实现资源加锁》数据共享是一把双刃剑,Go语言为我们提供了sync.Mutex,一种最基础也是最常用的加锁方式,用于保证在任意时刻只有一个goroutine能访问共享... 目录一、什么是 Mutex二、为什么需要加锁三、实战案例:并发安全的计数器1. 未加锁示例(存在竞态)

基于Redisson实现分布式系统下的接口限流

《基于Redisson实现分布式系统下的接口限流》在高并发场景下,接口限流是保障系统稳定性的重要手段,本文将介绍利用Redisson结合Redis实现分布式环境下的接口限流,具有一定的参考价值,感兴趣... 目录分布式限流的核心挑战基于 Redisson 的分布式限流设计思路实现步骤引入依赖定义限流注解实现

SpringBoot实现虚拟线程的方案

《SpringBoot实现虚拟线程的方案》Java19引入虚拟线程,本文就来介绍一下SpringBoot实现虚拟线程的方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录什么是虚拟线程虚拟线程和普通线程的区别SpringBoot使用虚拟线程配置@Async性能对比H

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

基于Python实现进阶版PDF合并/拆分工具

《基于Python实现进阶版PDF合并/拆分工具》在数字化时代,PDF文件已成为日常工作和学习中不可或缺的一部分,本文将详细介绍一款简单易用的PDF工具,帮助用户轻松完成PDF文件的合并与拆分操作... 目录工具概述环境准备界面说明合并PDF文件拆分PDF文件高级技巧常见问题完整源代码总结在数字化时代,PD

Python实现Word转PDF全攻略(从入门到实战)

《Python实现Word转PDF全攻略(从入门到实战)》在数字化办公场景中,Word文档的跨平台兼容性始终是个难题,而PDF格式凭借所见即所得的特性,已成为文档分发和归档的标准格式,下面小编就来和大... 目录一、为什么需要python处理Word转PDF?二、主流转换方案对比三、五套实战方案详解方案1:

SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南

《SpringBoot集成EasyExcel实现百万级别的数据导入导出实践指南》本文将基于开源项目springboot-easyexcel-batch进行解析与扩展,手把手教大家如何在SpringBo... 目录项目结构概览核心依赖百万级导出实战场景核心代码效果百万级导入实战场景监听器和Service(核心

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

基于Python Playwright进行前端性能测试的脚本实现

《基于PythonPlaywright进行前端性能测试的脚本实现》在当今Web应用开发中,性能优化是提升用户体验的关键因素之一,本文将介绍如何使用Playwright构建一个自动化性能测试工具,希望... 目录引言工具概述整体架构核心实现解析1. 浏览器初始化2. 性能数据收集3. 资源分析4. 关键性能指