当前位置: 首页 > 编程笔记 >

Android自定义控件实现饼状图

宋飞掣
2023-03-14
本文向大家介绍Android自定义控件实现饼状图,包括了Android自定义控件实现饼状图的使用技巧和注意事项,需要的朋友参考一下

本文实现一个如图所示的控件,包括两部分,左边的饼状图和中间的两个小方块,及右边的两行文字

实现起来比较简单,只是一些绘图API的调用

核心代码在onDraw函数里边,对静态控件进行绘制即可

@Override
protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 /**
 * 饼状图的x坐标
 */
 float centreX= getWidth()/5;
 /**
 * 饼状图的y坐标
 */
 float centreY= getHeight()/2;
 /**
 * 文字的大小
 */
 float textSize=getHeight()/7;
 float width=(float)getWidth();
 float height=(float)getHeight();
 /**
 * 中间小正方形边长的一半
 */
 float halfSmallRec =((float)getHeight())*3/70;
 percent =((float) mBigBallNumber)/(mBigBallNumber + mSmallBallNumber);
 /**
 * 求饼状图的半径
 */
 radius= Math.min(getWidth() * 1 / 8, getHeight() * 10 / 35);
 /**
 * 构建一个正方形,饼状图是这个正方形的内切圆
 */
 rectf=new RectF((int)(centreX-radius),(int)(centreY-radius),(int)(centreX+radius),(int)(centreY+radius));
 /**
 * 设置饼状图画笔的颜色,先绘制大球占的比例
 */
 piePaint.setColor(mBigBallColor);
 /* The arc is drawn clockwise. An angle of 0 degrees correspond to the
 * geometric angle of 0 degrees (3 o'clock on a watch.)*/
 /* drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)*/
 /**
 * 绘制大球的扇形图,float startAngle起始角度的0度的位置在3点钟方向
 * 因此大球的扇形图要从12点钟开始绘制,所以起始角度为270度
 */
 canvas.drawArc(rectf, 270, 360 * percent, true, piePaint);
 /**
 * 换种颜色,开始绘制小球占的饼状图
 */
 piePaint.setColor(mSmallBallColor);
 /**
 * 起始角度就是12点钟加上360度乘以大球占的比例,12点钟转换为起始角度为270度
 */
 canvas.drawArc(rectf, 270 + 360 * percent, 360 - 360 * percent, true, piePaint);
 颜色更改为大球的颜色*/
 piePaint.setColor(mBigBallColor);
 /**
 * 绘制上边的小方块,也就是大球的方块
 */
 canvas.drawRect(width * 2 / 5 - halfSmallRec, height* 23/ 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height *23/ 60 + halfSmallRec, piePaint);
 /**
 * 更改画笔颜色为小球颜色
 */
 piePaint.setColor(mSmallBallColor);
 /**
 * 绘制下边的小方块即小球的小方块
 */
 canvas.drawRect(width * 2 / 5 - halfSmallRec, height * 37 / 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height * 37 / 60 + halfSmallRec, piePaint);
 /**
 * 开始绘制文字,先设置文字颜色
 */
 textPaint.setColor(getResources().getColor(typedValue.resourceId));
 /**
 * 设置问题大小
 */
 textPaint.setTextSize(textSize);
 /**
 * 大球数量
 */
 String strBig = strBigBallName + mBigBallNumber;
 /**
 * 测量文字宽度
 */
 float textBigWidth =textPaint.measureText(strBig);
 Paint.FontMetrics fontMetrics=textPaint.getFontMetrics();
 /**
 * 绘制上边大球数量
 */
 canvas.drawText(strBig, width * 9 / 20 + textBigWidth / 2, height *23/ 60 - fontMetrics.top / 3, textPaint);
 /**
 * 小球数量
 */
 String strSmall = strSmallBallName + mSmallBallNumber;
 /**
 * 测量文字宽度
 */
 float textUnderWidth=textPaint.measureText(strSmall);
 /**
 * 绘制下边的小球数量
 */
 canvas.drawText(strSmall,width*9/20+textUnderWidth/2,height*37/60-fontMetrics.top/3,textPaint);
 /**
 * 更改画笔颜色,开始绘制百分比
 */
 textPaint.setColor(getResources().getColor(R.color.half_transparent));
 String strBigPercent =" ("+ mPercentBigBall +")";
 /**
 * 测量大球百分比文字宽度
 */
 float bigPercent =textPaint.measureText(strBigPercent);
 /**drawText(String text, float x, float y, Paint paint)
 * 绘制文字的API,四个参数分别是文字内容,起始绘制x坐标,起始绘制y坐标,画笔
 * 以为设置了居中绘制,因此穿进去的xy坐标为文字的中心点
 */
 canvas.drawText(strBigPercent, width * 9 / 20+ textBigWidth + bigPercent /2, height*23 / 60-fontMetrics.top*1/3, textPaint);
 /**
 * 同样的道理绘制小球的百分比
 */
 String strSmallPercent =" ("+ mPercentSmallBall +")";
 float smallPercent =textPaint.measureText(strSmallPercent);
 canvas.drawText(strSmallPercent,width*9/20+textUnderWidth+ smallPercent /2,height*37/60-fontMetrics.top/3,textPaint);
}

Canvas 绘制文本时,使用FontMetrics对象,计算位置的坐标。参考:使用FontMetrics对象计算位置坐标

设置文字绘制以中心为起点开始绘制

textPaint.setTextAlign(Paint.Align.CENTER);

x的坐标好计算,y坐标需要按需使用FontMetrics几个属性即可

完整代码如下:

public class PieHalfView extends View {
 /**
 * 左边饼状图的画笔
 */
 private Paint piePaint;
 /**
 * 右边文字的画笔
 */
 private Paint textPaint;
 /**
 * 饼状图的半径
 */
 private float radius;
 private RectF rectf;
 /**
 * 饼状图中第一个扇形占整个圆的比例
 */
 private float percent;
 /**
 * 深浅两种颜色
 */
 private int mBigBallColor, mSmallBallColor;
 /**
 * 大小球的数量
 */
 private int mBigBallNumber;
 private int mSmallBallNumber;
 /**
 * 大小球所占的百分比
 */
 private String mPercentBigBall;
 private String mPercentSmallBall;
 /**
 * 动态获取属性
 */
 private TypedValue typedValue;
 /**
 * 中间的文字信息
 */
 private String strBigBallName;
 private String strSmallBallName;
 
 public PieHalfView(Context context) {
 super(context);
 init(context);
 }
 
 public PieHalfView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init(context);
 }
 
 public PieHalfView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init(context);
 }
 private void init(Context context) {
 /**
 * 设置饼状图画笔
 */
 piePaint =new Paint();
 piePaint.setAntiAlias(true);
 piePaint.setStyle(Paint.Style.FILL);
 /**
 * 设置文字画笔
 */
 textPaint=new Paint();
 textPaint.setStyle(Paint.Style.STROKE);
 textPaint.setAntiAlias(true);
 textPaint.setTextAlign(Paint.Align.CENTER);
 /**
 * 下边设置一些默认的值,如果调用者没有传值进来的话,用这些默认值
 */
 mBigBallColor = 0xFF9CCA5D;
 mSmallBallColor =0xFF5F7048;
 /*TypedValue:Container for a dynamically typed data value. Primarily used with Resources for holding resource values.*/
 typedValue=new TypedValue();
 context.getTheme().resolveAttribute(R.attr.maintextclor,typedValue,true);
 mBigBallNumber =1;
 mSmallBallNumber =3;
 mPercentBigBall ="40%";
 mPercentSmallBall ="60%";
 strBigBallName =getResources().getString(R.string.big);
 strSmallBallName =getResources().getString(R.string.small);
 }
 
 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 /**
 * 饼状图的x坐标
 */
 float centreX= getWidth()/5;
 /**
 * 饼状图的y坐标
 */
 float centreY= getHeight()/2;
 /**
 * 文字的大小
 */
 float textSize=getHeight()/7;
 float width=(float)getWidth();
 float height=(float)getHeight();
 /**
 * 中间小正方形边长的一半
 */
 float halfSmallRec =((float)getHeight())*3/70;
 percent =((float) mBigBallNumber)/(mBigBallNumber + mSmallBallNumber);
 /**
 * 求饼状图的半径
 */
 radius= Math.min(getWidth() * 1 / 8, getHeight() * 10 / 35);
 /**
 * 构建一个正方形,饼状图是这个正方形的内切圆
 */
 rectf=new RectF((int)(centreX-radius),(int)(centreY-radius),(int)(centreX+radius),(int)(centreY+radius));
 /**
 * 设置饼状图画笔的颜色,先绘制大球占的比例
 */
 piePaint.setColor(mBigBallColor);
 /* The arc is drawn clockwise. An angle of 0 degrees correspond to the
 * geometric angle of 0 degrees (3 o'clock on a watch.)*/
 /* drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)*/
 /* 绘制大球的扇形图,float startAngle起始角度的0度的位置在3点钟方向
 * 因此大球的扇形图要从12点钟开始绘制,所以起始角度为270度*/
 canvas.drawArc(rectf, 270, 360 * percent, true, piePaint);
 /**
 * 换种颜色,开始绘制小球占的饼状图
 */
 piePaint.setColor(mSmallBallColor);
 /**
 * 起始角度就是12点钟加上360度乘以大球占的比例,12点钟转换为起始角度为270度
 */
 canvas.drawArc(rectf, 270 + 360 * percent, 360 - 360 * percent, true, piePaint);
 /**
 * 颜色更改为大球的颜色*/
  piePaint.setColor(mBigBallColor);
 /**
 * 绘制上边的小方块,也就是大球的方块
 */
 canvas.drawRect(width * 2 / 5 - halfSmallRec, height* 23/ 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height *23/ 60 + halfSmallRec, piePaint);
 /**
 * 更改画笔颜色为小球颜色
 */
 piePaint.setColor(mSmallBallColor);
 /**
 * 绘制下边的小方块即小球的小方块
 */
 canvas.drawRect(width * 2 / 5 - halfSmallRec, height * 37 / 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height * 37 / 60 + halfSmallRec, piePaint);
 /**
 * 开始绘制文字,先设置文字颜色
 */
 textPaint.setColor(getResources().getColor(typedValue.resourceId));
 /**
 * 设置问题大小
 */
 textPaint.setTextSize(textSize);
 /**
 * 大球数量
 */
 String strBig = strBigBallName + mBigBallNumber;
 /**
 * 测量文字宽度
 */
 float textBigWidth =textPaint.measureText(strBig);
 Paint.FontMetrics fontMetrics=textPaint.getFontMetrics();
 /**
 * 绘制上边大球数量
 */
 canvas.drawText(strBig, width * 9 / 20 + textBigWidth / 2, height *23/ 60 - fontMetrics.top / 3, textPaint);
 /**
 * 小球数量
 */
 String strSmall = strSmallBallName + mSmallBallNumber;
 /**
 * 测量文字宽度
 */
 float textUnderWidth=textPaint.measureText(strSmall);
 /**
 * 绘制下边的小球数量
 */
 canvas.drawText(strSmall,width*9/20+textUnderWidth/2,height*37/60-fontMetrics.top/3,textPaint);
 /**
 * 更改画笔颜色,开始绘制百分比
 */
 textPaint.setColor(getResources().getColor(R.color.half_transparent));
 String strBigPercent =" ("+ mPercentBigBall +")";
 /**
 * 测量大球百分比文字宽度*/
 float bigPercent =textPaint.measureText(strBigPercent);
 /** drawText(String text, float x, float y, Paint paint)
 * 绘制文字的API,四个参数分别是文字内容,起始绘制x坐标,起始绘制y坐标,画笔
 * 以为设置了居中绘制,因此穿进去的xy坐标为文字的中心点
 */
 canvas.drawText(strBigPercent, width * 9 / 20+ textBigWidth + bigPercent /2, height*23 / 60-fontMetrics.top*1/3, textPaint);
 /*
 * 同样的道理绘制小球的百分比
 */
 String strSmallPercent =" ("+ mPercentSmallBall +")";
 float smallPercent =textPaint.measureText(strSmallPercent);
 canvas.drawText(strSmallPercent,width*9/20+textUnderWidth+ smallPercent /2,height*37/60-fontMetrics.top/3,textPaint);
 }
 public void setPercent(float percent1){
 this.percent =percent1;
 invalidate();
 }
 public void setColor(int mBigBallColor,int mSmallBallColor){
 this.mBigBallColor =mBigBallColor;
 this.mSmallBallColor =mSmallBallColor;
 invalidate();
 }
 
 public void setOverRunner(String bigPecent, String smallPercent, int big, int small,
 int bigColor, int smallColor){
 this.mPercentBigBall = bigPecent;
 this.mPercentSmallBall = smallPercent;
 this.mBigBallNumber = big;
 this.mSmallBallNumber = small;
 this.mBigBallColor = bigColor;
 this.mSmallBallColor = smallColor;
 invalidate();
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍Android自定义控件(实现状态提示图表),包括了Android自定义控件(实现状态提示图表)的使用技巧和注意事项,需要的朋友参考一下 前面分析那么多系统源码了,也该暂停下来休息一下,趁昨晚闲着看见一个有意思的需求就操练一下分析源码后的实例演练—-自定义控件。 这个实例很适合新手入门自定义控件。先看下效果图: 横屏模式如下: 竖屏模式如下: 看见没有,这个控件完全自定义的,连文字等

  • 本文向大家介绍Android自定义View实现饼状图带动画效果,包括了Android自定义View实现饼状图带动画效果的使用技巧和注意事项,需要的朋友参考一下 一个简单的自定义view饼状图,加入了动画效果 先看一下效果 下面就直接上代码了 已经加入了详细的注释,同样的原理,还可以将动画加入到柱形图等等。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 本文向大家介绍Android自定义控件实现折线图,包括了Android自定义控件实现折线图的使用技巧和注意事项,需要的朋友参考一下 本文实例实现一个如下图所示的Android折线图,供大家参考,具体内容如下 首先是控件绘图区域的划分,控件左边取一小部分(控件总宽度的八分之一)绘制表头,右边剩余的部分绘制表格 确定表格的行列数,首先绘制一个三行八列的网格,设置好行列的坐标后开始绘制 网格绘制完成后,

  • 本文向大家介绍安卓(Android)开发之自定义饼状图,包括了安卓(Android)开发之自定义饼状图的使用技巧和注意事项,需要的朋友参考一下 先来看看效果图 先分析饼状图的构成,非常明显,饼状图就是一个又一个的扇形构成的,每个扇形都有不同的颜色,对应的有名字,数据和百分比。 经以上信息可以得出饼状图的最基本数据应包括:名字 数据值 百分比 对应的角度 颜色。   用户关心的数据 : 名字 数据值

  • 本文向大家介绍Android自定义控件实现简单的轮播图控件,包括了Android自定义控件实现简单的轮播图控件的使用技巧和注意事项,需要的朋友参考一下 最近要做一个轮播图的效果,网上看了几篇文章,基本上都能找到实现,效果还挺不错,但是在写的时候感觉每次都要单独去重新在Activity里写一堆代码。于是自己封装了一下。本篇轮播图实现原理原文出处:循环广告位组件的实现,这里只是做了下封装成一个控件,不

  • 本文向大家介绍Android自定义控件实现手势密码,包括了Android自定义控件实现手势密码的使用技巧和注意事项,需要的朋友参考一下 Android手势解锁密码效果图       首先呢想写这个手势密码的想法呢,完全是凭空而来的,然后笔者就花了一天时间弄出来了。本以为这个东西很简单,实际上手的时候发现,还有很多逻辑需要处理,稍不注意就容易乱套。写个UI效果图大约只花了3个小时,但是处理逻辑就处理