Android编程实现canvas绘制饼状统计图功能示例【自动适应条目数量与大小】
作者:books1958 发布时间:2023-05-10 23:27:41
标签:Android,canvas,绘制
本文实例讲述了Android编程实现canvas绘制饼状统计图功能。分享给大家供大家参考,具体如下:
本例的目的是实现一个简单的饼状统计图,效果如下:
特点:
1.使用非常方便,可放在xml布局文件中,然后在代码中设置内容,即:
PieChartView pieChartView = (PieChartView) findViewById(R.id.pie_chart);
PieChartView.PieItemBean[] items = new PieChartView.PieItemBean[]{
new PieChartView.PieItemBean("娱乐", 200),
new PieChartView.PieItemBean("旅行", 100),
new PieChartView.PieItemBean("学习", 120),
new PieChartView.PieItemBean("人际关系", 160),
new PieChartView.PieItemBean("交通", 100),
new PieChartView.PieItemBean("餐饮", 480)
};
pieChartView.setPieItems(items);
2.条目数量,大小及折线位置,长度均自适应。左侧条目往左侧划线,右侧条目往右侧划线,文字描述与百分比居中对齐,并且文字“下划线”与文字长度自适应。对于很小的条目,将自动将折线延长以尽可能避免文字遮盖
核心代码:PieChartView.Java:
public class PieChartView extends View {
private int screenW, screenH;
/**
* The paint to draw text, pie and line.
*/
private Paint textPaint, piePaint, linePaint;
/**
* The center and the radius of the pie.
*/
private int pieCenterX, pieCenterY, pieRadius;
/**
* The oval to draw the oval in.
*/
private RectF pieOval;
private float smallMargin;
private int[] mPieColors = new int[]{Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.MAGENTA, Color.CYAN};
private PieItemBean[] mPieItems;
private float totalValue;
public PieChartView(Context context) {
super(context);
init(context);
}
public PieChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PieChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
//init screen
screenW = ScreenUtils.getScreenW(context);
screenH = ScreenUtils.getScreenH(context);
pieCenterX = screenW / 2;
pieCenterY = screenH / 3;
pieRadius = screenW / 4;
smallMargin = ScreenUtils.dp2px(context, 5);
pieOval = new RectF();
pieOval.left = pieCenterX - pieRadius;
pieOval.top = pieCenterY - pieRadius;
pieOval.right = pieCenterX + pieRadius;
pieOval.bottom = pieCenterY + pieRadius;
//The paint to draw text.
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setTextSize(ScreenUtils.dp2px(context, 16));
//The paint to draw circle.
piePaint = new Paint();
piePaint.setAntiAlias(true);
piePaint.setStyle(Paint.Style.FILL);
//The paint to draw line to show the concrete text
linePaint = new Paint();
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(ScreenUtils.dp2px(context, 1));
}
//The degree position of the last item arc's center.
private float lastDegree = 0;
//The count of the continues 'small' item.
private int addTimes = 0;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPieItems != null && mPieItems.length > 0) {
float start = 0.0f;
for (int i = 0; i < mPieItems.length; i++) {
//draw pie
piePaint.setColor(mPieColors[i % mPieColors.length]);
float sweep = mPieItems[i].getItemValue() / totalValue * 360;
canvas.drawArc(pieOval, start, sweep, true, piePaint);
//draw line away from the pie
float radians = (float) ((start + sweep / 2) / 180 * Math.PI);
float lineStartX = pieCenterX + pieRadius * 0.7f * (float) (Math.cos(radians));
float lineStartY = pieCenterY + pieRadius * 0.7f * (float) (Math.sin(radians));
float lineStopX, lineStopY;
float rate;
if (getOffset(start + sweep / 2) > 60) {
rate = 1.3f;
} else if (getOffset(start + sweep / 2) > 30) {
rate = 1.2f;
} else {
rate = 1.1f;
}
//If the item is very small, make the text further away from the pie to avoid being hided by other text.
if (start + sweep / 2 - lastDegree < 30) {
addTimes++;
rate += 0.2f * addTimes;
} else {
addTimes = 0;
}
lineStopX = pieCenterX + pieRadius * rate * (float) (Math.cos(radians));
lineStopY = pieCenterY + pieRadius * rate * (float) (Math.sin(radians));
canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, linePaint);
//write text
String itemTypeText = mPieItems[i].getItemType();
String itemPercentText = Utility.formatFloat(mPieItems[i].getItemValue() / totalValue * 100) + "%";
float itemTypeTextLen = textPaint.measureText(itemTypeText);
float itemPercentTextLen = textPaint.measureText(itemPercentText);
float lineTextWidth = Math.max(itemTypeTextLen, itemPercentTextLen);
float textStartX = lineStopX;
float textStartY = lineStopY - smallMargin;
float percentStartX = lineStopX;
float percentStartY = lineStopY + textPaint.getTextSize();
if (lineStartX > pieCenterX) {
textStartX += (smallMargin + Math.abs(itemTypeTextLen - lineTextWidth) / 2);
percentStartX += (smallMargin + Math.abs(itemPercentTextLen - lineTextWidth) / 2);
} else {
textStartX -= (smallMargin + lineTextWidth - Math.abs(itemTypeTextLen - lineTextWidth) / 2);
percentStartX -= (smallMargin + lineTextWidth - Math.abs(itemPercentTextLen - lineTextWidth) / 2);
}
canvas.drawText(itemTypeText, textStartX, textStartY, textPaint);
//draw percent text
canvas.drawText(itemPercentText, percentStartX, percentStartY, textPaint);
//draw text underline
float textLineStopX = lineStopX;
if (lineStartX > pieCenterX) {
textLineStopX += (lineTextWidth + smallMargin * 2);
} else {
textLineStopX -= (lineTextWidth + smallMargin * 2);
}
canvas.drawLine(lineStopX, lineStopY, textLineStopX, lineStopY, linePaint);
lastDegree = start + sweep / 2;
start += sweep;
}
}
}
public PieItemBean[] getPieItems() {
return mPieItems;
}
public void setPieItems(PieItemBean[] pieItems) {
this.mPieItems = pieItems;
totalValue = 0;
for (PieItemBean item : mPieItems) {
totalValue += item.getItemValue();
}
invalidate();
}
private float getOffset(float radius) {
int a = (int) (radius % 360 / 90);
switch (a) {
case 0:
return radius;
case 1:
return 180 - radius;
case 2:
return radius - 180;
case 3:
return 360 - radius;
}
return radius;
}
static class PieItemBean {
private String itemType;
private float itemValue;
PieItemBean(String itemType, float itemValue) {
this.itemType = itemType;
this.itemValue = itemValue;
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public float getItemValue() {
return itemValue;
}
public void setItemValue(float itemValue) {
this.itemValue = itemValue;
}
}
}
完整实例代码点击此处本站下载。
希望本文所述对大家Android程序设计有所帮助。


猜你喜欢
- 前言在开发过程中需要快速新建getXXX();setXXX()方法的时候,就会想能否批量实现呢?例如实现如下代码,一次性操作,不是一个一个码
- C#动态webservice调用接口using System;using System.Collections;using System.I
- 前言:对于一个程序员来说,尤其是在java web端开发的程序员,三大框架:Struts+Hibernate+Spring是必须要掌握熟透的
- 历史原因当系统启动一个APP时,zygote进程会首先创建一个新的进程去运行这个APP,但是进程的创建是需要时间的,在创建完成之前,界面是呈
- merge标签合并标记需要两个或两个以上的列表作为参数,并把它们合并在一起,如下所示:<s:merge var="myMer
- 最近由于项目需求,需要做一个listview中的item策划删除的效果,与是查找资料和参考了一些相关的博客,终于完美实现了策划删除的效果。先
- 前言记得去年做一个聊天项目需要实现类似QQ的下拉刷新并且有侧滑删除的功能,在网上找了很久都没有QQ的完美,多多少少存在各种的问题,最后把下拉
- 目录推荐教程正文创建-服务端-生成代码创建客户端,生成客户端代码先下载soapUI工具推荐教程idea2021以下最新安装j ihuo 教程
- android studio版本:2021.2.1例程名称:pravicydialog功能:1、启动app后弹窗隐私协议2、屏蔽返回键3、再
- 我们的spring cloud微服务一般是打成jar包发布的,Linux下启动jar包和windows下一样,都是java -jar 包名,
- 上一篇文章我们介绍了Apache Commons Math3学习之数值积分实例代码,这里给大家分享math3多项式曲线拟合的相关内容,具体如
- 需求:Android调用webView加载网页的时候,拦截某一个链接不执行此链接,执行指定跳转到其他activity页面。webview的s
- 你知道String、StringBuilder、Stringbuffer的区别吗?当你创建字符串的时候,有考虑过该使用哪个吗?别急,这篇文章
- Bitmap (android.graphics.Bitmap)Bitmap是Android系统中的图像处理的最重要类之一。用它可以获取图像
- IDEA版本:2020.3具体步骤一、开启IDEA的自动编译【静态】1.File->Settings。2.直接搜索Compiler,选
- 本文实现Unity调用手机摄像,拍摄,然后识别二维码,显示二维码的内容。需要导入一个zxing.unity.dll文件,现在这个脚本的识别数
- 最近学习了 C#实现文件上传与下载,现在分享给大家。1、C#文件上传创建MyUpload.htm页面,用于测试<form name=&
- web 容器的设计开发一个web容器涉及很多不同方面不同层面的技术,例如通信层的知识,程序语言层面的知识等等,且一个可用的web容器是一个比
- 本文借由并发环境下使用线程不安全的SimpleDateFormat优化案例,帮助大家理解ThreadLocal.最近整理公司项目,发现不少写
- 前言本次示例代码的文件结构如下图所示。1. 导入依赖坐标在 order-service 的 pom.xml 文件中导入 Feign 的依赖坐