android 每个块半径不同的扇形图,自定义view
1.首先看效果图
2.自定义PieChartView,继承自View,下边为PieChartView代码
package com.yingjinbao.im.peach.customview; import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View; /**
* Created by wanger on 07/19/2018.
*/ public class PieChartView extends View { private int mHeight, mWidth;//宽高
private Paint mPaint;//扇形的画笔
private Paint mTextPaint;//画文字的画笔 private int centerX, centerY;//中心坐标 private int maxNum = 4;//扇形图的最大块数,超出部分自动合并到最后一块上去 double total;//数据的总和
double[] datas;//数据集
String[] texts;//每个数据对应的文字集 //颜色 默认的颜色
private int[] mColors = {
Color.parseColor("#FFC65B"), Color.parseColor("#FD5998"),
Color.parseColor("#8971FB"), Color.parseColor("#676974")
}; private int mTextSize;//文字大小 private int radius = 1000;//半径 public PieChartView(Context context) {
super(context);
} public PieChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
} //初始化
private void init() {
mTextSize = 25; mPaint = new Paint();
//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式, 如圆形样Cap.ROUND,或方形样式Cap.SQUARE
mPaint.setStrokeCap(Paint.Cap.ROUND);
//设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
mPaint.setAntiAlias(true); mTextPaint = new Paint();
//设置绘制文字的字号大小
mTextPaint.setTextSize(mTextSize);
//当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度
mTextPaint.setStrokeWidth(3);
//设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
mTextPaint.setAntiAlias(true);
//设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。
mTextPaint.setColor(Color.WHITE);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取宽高 不要设置wrap_content
mHeight = MeasureSpec.getSize(heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//无数据
if (datas == null || datas.length == 0) return; centerX = (getRight() - getLeft()) / 2;
centerY = (getBottom() - getTop()) / 2;
int min = mHeight > mWidth ? mWidth : mHeight;
if (radius > min / 2) {
radius = (int) ((min - getPaddingTop() - getPaddingBottom()) / 3.5);
} //画扇形
canvas.save();
drawCircle(canvas);
canvas.restore(); //线与文字
canvas.save();
drawLineAndText(canvas);
canvas.restore(); } //画线与文字
private void drawLineAndText(Canvas canvas) {
int start = 0;
canvas.translate(centerX, centerY);//平移画布到中心
mPaint.setStrokeWidth(4);
for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) { if (i == (maxNum < datas.length ? maxNum : datas.length) - 1){
drawLine(canvas, start, 360 - start, texts[i], mColors[i % mColors.length],i);
}else {
float angles = (float) ((datas[i] * 1.0f / total) * 360);
drawLine(canvas, start, angles, texts[i], mColors[i % mColors.length],i);
start += angles;
}
}
} private void drawLine(Canvas canvas, int start, float angles, String text, int color,int position) {
mPaint.setColor(color);
//mTextPaint.setColor(color);
float stopX, stopY;
stopX = (float) ((radius + 40) * Math.cos((2 * start + angles) / 2 * Math.PI / 180));
stopY = (float) ((radius + 40) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)); switch (position){
case 0:
canvas.drawLine((float) ((radius * 0.5) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.5) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 1:
canvas.drawLine((float) ((radius * 0.7) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.7) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 2:
canvas.drawLine((float) ((radius * 1.1) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 1.1) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 3:
canvas.drawLine((float) ((radius * 0.9) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.9) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
default:
canvas.drawLine((float) (radius * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) (radius * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
}
//canvas.drawLine(0, 0, stopX, stopY, mPaint);
//画横线
int dx;//判断横线是画在左边还是右边
int endX;
if (stopX > 0) {
endX = (int) (stopX + 110);
} else {
endX = (int) (stopX - 110);
}
//画横线
canvas.drawLine(stopX, stopY,
endX, stopY, mPaint
);
dx = (int) (endX - stopX); //测量文字大小
Rect rect = new Rect();
mTextPaint.getTextBounds(text, 0, text.length(), rect);
int w = rect.width();
int h = rect.height();
int offset = 20;//文字在横线的偏移量
//画文字
canvas.drawText(text, 0, text.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY - 5, mTextPaint); //测量百分比大小
String percentage = (datas[position] / total) * 100 + "";
percentage = percentage.substring(0, percentage.length() > 4 ? 4 : percentage.length()) + "%";
mTextPaint.getTextBounds(percentage, 0, percentage.length(), rect);
w = rect.width() - 10;
//画百分比
canvas.drawText(percentage, 0, percentage.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY + h, mTextPaint); } //画扇形
private void drawCircle(Canvas canvas) {
RectF rect = null;
int start = 0;
for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) {
if (i == 0){
rect = new RectF((float) (centerX - radius * 0.5), (float) (centerY - radius * 0.5),
(float) (centerX + radius * 0.5), (float) (centerY + radius * 0.5));
}else if (i == 1){
rect = new RectF((float) (centerX - radius * 0.7), (float) (centerY - radius * 0.7),
(float) (centerX + radius * 0.7), (float) (centerY + radius * 0.7));
}else if (i == 2){
rect = new RectF((float) (centerX - radius * 1.1), (float) (centerY - radius * 1.1),
(float) (centerX + radius * 1.1), (float) (centerY + radius * 1.1));
}else if (i == 3){
rect = new RectF((float) (centerX - radius * 0.9), (float) (centerY - radius * 0.9),
(float) (centerX + radius * 0.9), (float) (centerY + radius * 0.9));
}else {
rect = new RectF((float) (centerX - radius * 1), (float) (centerY - radius * 1),
(float) (centerX + radius * 1), (float) (centerY + radius * 1));
} if (i == (maxNum < datas.length ? maxNum : datas.length) - 1){
float angles = 360 - start;
mPaint.setColor(mColors[i % mColors.length]); if (i == 2){
canvas.drawArc(rect, start, angles, true, mPaint); mPaint.setColor(Color.parseColor("#34374A"));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(8);
rect = new RectF((float) (centerX - radius * 1.03), (float) (centerY - radius * 1.03),
(float) (centerX + radius * 1.03), (float) (centerY + radius * 1.03)); canvas.drawArc(rect, start, angles, false, mPaint);
init();
}else {
canvas.drawArc(rect, start, angles, true, mPaint);
} start += angles;
}else {
float angles = (float) ((datas[i] * 1.0f / total) * 360);
mPaint.setColor(mColors[i % mColors.length]); if (i == 2){
canvas.drawArc(rect, start, angles, true, mPaint); mPaint.setColor(Color.parseColor("#34374A"));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(8);
rect = new RectF((float) (centerX - radius * 1.03), (float) (centerY - radius * 1.03),
(float) (centerX + radius * 1.03), (float) (centerY + radius * 1.03)); canvas.drawArc(rect, start, angles, false, mPaint);
init();
}else {
canvas.drawArc(rect, start, angles, true, mPaint);
} start += angles;
}
}
} //setter
public void setColors(int[] mColors) {
this.mColors = mColors;
invalidate();
} public void setTextSize(int mTextSize) {
this.mTextSize = mTextSize;
mTextPaint.setTextSize(mTextSize);
invalidate();
} public void setRadius(int radius) {
this.radius = radius;
invalidate();
} public void setMaxNum(int maxNum) {
this.maxNum = maxNum;
invalidate();
} public void setDatas(double[] datas) {
this.datas = datas;
total = 0;
for (int i = 0;i < datas.length;i++){
total += datas[i];
}
} public void setTexts(String[] texts) {
this.texts = texts;
} }
3.使用,首先在XML文件中调用
之后,在activity中,只需找到组件,传入数据,调用 invalidate() 进行重绘即可。
android 每个块半径不同的扇形图,自定义view的更多相关文章
- Android零基础入门第24节:自定义View简单使用
原文:Android零基础入门第24节:自定义View简单使用 当我们开发中遇到Android原生的组件无法满足需求时,这时候就应该自定义View来满足这些特殊的组件需求. 一.概述 很多初入Andr ...
- Android UI 绘制过程浅析(五)自定义View
前言 这已经是Android UI 绘制过程浅析系列文章的第五篇了,不出意外的话也是最后一篇.再次声明一下,这一系列文章,是我在拜读了csdn大牛郭霖的博客文章<带你一步步深入了解View> ...
- [转]Android自定义控件三部曲系列完全解析(动画, 绘图, 自定义View)
来源:http://blog.csdn.net/harvic880925/article/details/50995268 一.自定义控件三部曲之动画篇 1.<自定义控件三部曲之动画篇(一)—— ...
- Android开发之漫漫长途 番外篇——自定义View的各种姿势1
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android开发之漫漫长途 番外篇——自定义View的各种姿势2
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- Android简易实战教程--第二十七话《自定义View入门案例之开关按钮详细分析》
转载此博客请注明出处点击打开链接 http://blog.csdn.net/qq_32059827/article/details/52444145 对于自定义view,可能是一个比较大的 ...
- Android 麦克风录音带音量大小动态显示的圆形自定义View
1.所谓无图无真相,先上效果图.我们要实现的就是中间那个录音的按钮,周边会显示一圈音量大小的波形 2.VolumCircleBar继承自View,我们进行了自定义,代码如下 package com.r ...
- Android零基础入门第52节:自定义酷炫进度条
原文:Android零基础入门第52节:自定义酷炫进度条 Android系统默认的ProgressBar往往都不能满足实际开发需要,一般都会开发者自定义ProgressBar. 在Android开发中 ...
- 【朝花夕拾】Android自定义View篇之(八)多点触控(上)MotionEvent简介
前言 在前面的文章中,介绍了不少触摸相关的知识,但都是基于单点触控的,即一次只用一根手指.但是在实际使用App中,常常是多根手指同时操作,这就需要用到多点触控相关的知识了.多点触控是在Android2 ...
随机推荐
- AngularJS入门之数据验证
AngularJS自带了对表单或控件的输入数据进行验证的功能,对于Html5的基础控件均有内建的验证器,以下列举了所有支持的验证类型: email max maxlength min minlengt ...
- Java Web入门学习(四)Eclipse与Maven、Tomcat整合配置 (重整版并解决问题)
Java Web学习(四)Eclipse与Maven整合配置 (重整版) 一.准备工作 1.Tomcat 8.5.15 2.Maven3.5 3.Eclipse Neon.3 Release (4.6 ...
- MySQl资料链接
原文:http://www.uml.org.cn/sjjm/sjjm-MySql.asp MySQl MySQL高可用数据库内核深度优化的四重定制 MySQL数据表存储引擎类型及特性 My ...
- JVM调优一些相关内容
JVM调优工具 Jconsole,jProfile,VisualVM Jconsole : jdk自带,功能简单,但是可以在系统有一定负荷的情况下使用.对垃圾回收算法有很详细的跟踪.详细说明参考这里 ...
- Java性能调优:利用VisualVM进行性能分析
JVisualVM 简介 VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC ...
- 面试题21:如何判断二叉树是搜索二叉树BST?
Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...
- ASP.NET Core 中的对象映射之 AutoMapper
目录 AutoMapper 简介 AutoMapper 使用 初始化 Profile设置 扁平化映射 集合映射 投影 条件映射 值转换 设置转换前后行为 配置验证及设置 反向映射 自定义转换器 自定义 ...
- [BZOJ 5074]小B的数字
Description 题库链接 给你一个长度为 \(n\) 的序列 \(a_1,a_2,\cdots,a_n\) ,让你生成另一个序列 \(b_1,b_2,\cdots,b_n\) ,使得 \(\f ...
- 本地git关联远程github
0. 前言 我们开发的项目,均在本地开发:为了保证项目进度的一致性和公开性等,我们通常将开发过程代码或成品放置到github中,本文就讲述如何使得本地git与远程github同步! PS:以下两个名称 ...
- 使用DateTime的ParseExact方法实现特殊日期时间的方法详解(转)
本篇文章是对使用DateTime的ParseExact方法实现特殊日期时间的方法进行了详细的分析介绍,需要的朋友参考下 今天遇到一个特别的需求,需要从下面的字符串中转换成一个DateTime对象: [ ...