我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android自定义View——扇形统计图的实现代码

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android自定义View——扇形统计图的实现代码

Android 扇形统计图

先看看效果:

看上去如果觉得还行就继续往下看吧!

自定义View

定义成员变量


  private int mHeight, mWidth;//宽高
  private Paint mPaint;//扇形的画笔
  private Paint mTextPaint;//画文字的画笔
  private int centerX, centerY;//中心坐标
  //"其他"的value
  //扇形图分成太多快 所以要合并一部分为其他 即图中灰色部分
  private double rest;
  private int maxNum = 5;//扇形图的最大块数 超过的item就合并到其他
  String others = "其他";//“其他”块要显示的文字
  double total;//数据的总和 
  double[] datas;//数据集
  String[] texts;//每个数据对应的文字集
  //颜色 默认的颜色
  private int[] mColors = {
      Color.parseColor("#FF4081"), Color.parseColor("#ffc0cb"),
      Color.parseColor("#00ff00"), Color.parseColor("#0066ff"), Color.parseColor("#ffee00")
  };
  private int mTextSize;//文字大小 单位:像素
  private int radius = 1000;//半径 在画图时初始化

测量宽高


  @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);
  }
  //画各个扇形
  drawCircle(canvas);
  //画线与文字
  drawLineAndText(canvas);
}

画扇形

一个圆形统计图是由许多个扇形组成的,我们根据数据计算出每个扇形的角度即可。注意,画弧度的时候,角度是顺时针变大的!即与我们平时的坐标是反过来的


  //画扇形
  private void drawCircle(Canvas canvas) {
    int centerX =( getRight() - getLeft() )/2;//中点
    int centerY = ( getBottom() - getTop()) /2;
    RectF rect = new RectF((float) (centerX - radius), centerY-radius,
        centerX+radius,centerY+radius);//圆形区域
    int start = 0;//扇形开始的角度
    for (int i = 0; i < (maxNum<datas.length?maxNum:datas.length); i++) {
      float angles = (float) ((datas[i] * 1.0f /total) * 360);//计算扇形的角度
      mPaint.setColor(mColors[i%mColors.length]);//颜色
      canvas.drawArc(rect,start,angles,true,mPaint);//画扇形
      start += angles;//下一个扇形开始的角度
    }
    //画"其他"部分 即图中灰色的部分
    rest =0;//保存其他部分的value
    for(int i=maxNum;i<datas.length;i++){
      rest+=datas[i];
    }
    float angles = (float) 360 - start;//角度
    mPaint.setColor(Color.GRAY);
    canvas.drawArc(rect,start,angles,true,mPaint);
  }

画线条和文字

主要是计算各个点的坐标很烦

这里我画出一个图 大家把代码和图对照理解一下


//画线与文字
  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++) {
      float angles = (float) ((datas[i] * 1.0f / total) * 360);
      //画线条和文字
      drawLine(canvas, start, angles, texts[i], mColors[i % mColors.length]);
      start += angles;
    }
    //画其他部分的线条和文字
    if (start < 360)//如果start小于360 说明有其他部分
      drawLine(canvas, start, 360 - start, others, Color.GRAY);
  }
  private void drawLine(Canvas canvas, int start, float angles, String text, int color) {
    mPaint.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));
    canvas.drawLine((float) ((radius - 20) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
        (float) ((radius - 20) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
        stopX, stopY, mPaint
    );
    //画横线
    int dx;//判断横线是画在左边还是右边
    int endX;
    if (stopX > 0) {
      endX = (centerX - getPaddingRight() - 20);
    } else {
      endX = (-centerX + getPaddingLeft() + 20);
    }
    //画横线
    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;//文字在横线的偏移量
    //画文字 文字的Y坐标值的是文字底部的Y坐标
    canvas.drawText(text, 0, text.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY + h, mTextPaint);
    //测量百分比大小
    String percentage = angles / 3.60 + "";
    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 - 5, mTextPaint);
  }

这样我们就已经完成了绘制的工作了,接下来就是绑定数据啦!

大家只要把datas和texts填充好数据就可以啦,最好调用一下invalidate()方法请求重绘(如果已经绘制了)。

我使用了一个内部抽象类来实现数据绑定的:


  public abstract class ArcViewAdapter<T> {
    public void setData(List<T> list) {
      datas = new double[list.size()];
      texts = new String[list.size()];
      for (int i = 0; i < list.size(); i++) {
        total += getValue(list.get(i));
        datas[i] = getValue(list.get(i));
        texts[i] = getText(list.get(i));
      }
      invalidate();//请求重绘
    }
    //通过传来的数据集的某个元素 得到具体的数字
    public abstract double getValue(T t);
    //通过传来的数据集的某个元素 得到具体的描述
    public abstract String getText(T t);
  }

在布局文件里面引用这个ArcView,然后在MainActivity中绑定数据:


ArcView arcView = (ArcView) findViewById(R.id.arc);
    List<Times> times = new ArrayList<>();
    for (int i = 6; i > 0; i--) {
      Times t = new Times();//这个类就只有两个变量
      t.hour = i;
      t.text = "Number"+i;
      times.add(t);
    }
    //初始化适配器
    ArcView.ArcViewAdapter myAdapter = arcView.new ArcViewAdapter<Times>(){
      @Override
      public double getValue(Times times) {
        return times.hour;
      }
      @Override
      public String getText(Times times) {
        return times.text;
      }
    };
    myAdapter.setData(times);//绑定数据

大家可以设置各种setter以便在Activity中调用,来提高ArcView的灵活性,比如设置颜色、半径、最大块数等等。

demo下载地址:SectorDiagram_jb51.rar

您可能感兴趣的文章:Android编程实现canvas绘制饼状统计图功能示例【自动适应条目数量与大小】Android编程实现canvas绘制柱状统计图功能【自动计算宽高及分度值、可左右滑动】Android 实现会旋转的饼状统计图实例代码Android自定义View实现多边形统计图示例代码


免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android自定义View——扇形统计图的实现代码

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android自定义View——扇形统计图的实现代码

Android 扇形统计图 先看看效果: 看上去如果觉得还行就继续往下看吧!自定义View 定义成员变量private int mHeight, mWidth;//宽高private Paint mPaint;//扇形的画笔private
2022-06-06

Android自定义扇形倒计时实例代码

一.概述 严格来说,我是Android小白,写的目的只是想作为知识储备而已….但是想到别人或许会不小心搜到我的这篇,如果我只是简单的描述,别人有可能看不懂,说不定还被吐槽,那岂不是很冤吗 所以,我还是把问题及过程描述清楚,这也是对自己的一个
2022-06-06

Android自定义View实现shape图形绘制

概述 之前曾写过一篇文章介绍了Android中drawable使用Shape资源,通过定义drawable中的shape资源能够绘制简单的图形效果,如矩形,椭圆形,线形和圆环等。后来我在项目中正好遇到这样一个需求,要在特定的位置上显示一条垂
2022-06-06

Android 自定义View之倒计时实例代码

Android 自定义View之倒计时实例代码 需求:大多数app在注册的时候,都有一个获取验证码的按钮,点击后,访问接口,最终用户会收到短信验证码。为了不多次写这个获取验证码的接口,下面将它自定义成一个view,方便使用。 分析一下,这是
2022-06-06

Android自定义View实现字母导航栏的代码

思路分析: 1、自定义View实现字母导航栏 2、ListView实现联系人列表 3、字母导航栏滑动事件处理 4、字母导航栏与中间字母的联动 5、字母导航栏与ListView的联动 效果图:首先,我们先甩出主布局文件,方便后面代码的说明
2022-06-06

Android自定义view实现雪花特效实例代码

实现雪花的效果其实也可以通过自定义View的方式来实现的,而且操作上也相对简单一些,下面这篇文章主要给大家介绍了关于Android自定义view实现雪花特效的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2022-12-28

Android自定义view实现圆形、圆角和椭圆图片(BitmapShader图形渲染)

一、前言 Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的。实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader。本文直接继承ImageView,使用BitmapS
2022-06-06

Android自定义View实现简单的圆形Progress效果

先给大家展示下效果图,如果感觉不错,请参考实现思路:我们要实现一个自定义的再一个圆形中绘制一个弧形的自定义View,思路是这样的:先要创建一个类ProgressView,继承自View类,然后重写其中的两个构造方法,一个是一个参数的,一个是
2022-06-06

android 自定义圆角button效果的实例代码(自定义view Demo)

概述 在平时开发过程中经常会碰到需要使用圆角button的情况,一般也会包括很多其他小功能,比如要在里面添加img,设置不同的圆角大小等。针对这样的场景,直接使用创建多个shape,定义多个xml文件也是可以实现的。但是如果使用非常频繁,那
2022-06-06

Android 实现自定义圆形进度条的实例代码

Android 自定义圆形进度条 今天无意中发现一个圆形进度,想想自己实现一个,如下图:基本思路是这样的: 1.首先绘制一个实心圆 2.绘制一个白色实心的正方形,遮住实心圆 3.在圆的中心动态绘制当前进度的百分比字符 4.绘制一个与之前实心
2022-06-06

Android中怎么通过自定义View实现圆形切图效果

本篇文章给大家分享的是有关Android中怎么通过自定义View实现圆形切图效果,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。实现思路使用一个Paint,将得到的Bitmap设
2023-05-30

Android自定义View实现带数字的进度条实例代码

第一步、效果展示 图1、蓝色的进度条 图2、红色的进度条 图3、多条颜色不同的进度条 图4、多条颜色不同的进度条第二步、自定义ProgressBar实现带数字的进度条 0、项目结构如上图所示:library项目为自定义的带数字的进度条Num
2022-06-06

Android 自定义dialog的实现代码

Android 自定义dialog的实现代码 搜索相关关键字网上一大堆实现,但是看完总觉得缺胳膊少腿,绕了不少弯路,终于弄好了自定义dialog。把自己整合的完整代码发上来。要点:1、设置自定义dialog的布局文件my_dialog.xm
2022-06-06

Android自定义控件之圆形/圆角的实现代码

一、问题在哪里? 问题来源于app开发中一个很常见的场景——用户头像要展示成圆的: 二、怎么搞? 机智的我,第一想法就是,切一张中间圆形透明、四周与底色相同、尺寸与头像相同的蒙板图片,盖在头像上不就完事了嘛,哈哈哈! 在背景纯色的前提下,这
2022-06-06

Android自定义软键盘的设计与实现代码

偶然间发现了Android.inputmethodservice.Keyboard类,即android可以自定义键盘类,做了一个简单例子供大家参考。效果如下:先看界面布局文件2022-06-06

Android自定义View实现环形进度条的思路与实例

前言 前段时间看到了豆瓣FM的音乐播放界面,有一个环形的进度条,非常的好看,于是想了想,为什么不自己做一个呢,于是就开始了自定义的过程豆瓣FM的播放界面如下图:功能分析 虽然功能比较简单,但是仍然需要仔细分析 1.图标外还有一圈圆
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录