全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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  # 扇形统计图  # 自定义圆view  # android自定义环形统计图动画  # Android自定义条形对比统计图  # Android自定义View实现多边形统计图示例代码  # Android编程实现canvas绘制饼状统计图功能示例【自动适应条目数量与大小】  # Android编程实现canvas绘制柱状统计图功能【自动计算宽高及分度值、可左右滑动】  # Android 实现会旋转的饼状统计图实例代码  # Android自定义控件横向柱状统计图  # 绑定  # 画线  # 图中  # 的是  # 并到  # 统计图  # 太多  # 下载地址  # 是由  # 是从  # 要把  # 自定义  # 过大  # 往下  # 来实现  # 看吧  # 还行  # 画出  # 变大  # 大家多多 


相关文章: 如何快速打造个性化非模板自助建站?  长沙企业网站制作哪家好,长沙水业集团官方网站?  专业公司网站制作公司,用什么语言做企业网站比较好?  如何优化Golang Web性能_Golang HTTP服务器性能提升方法  如何批量查询域名的建站时间记录?  北京企业网站设计制作公司,北京铁路集团官方网站?  昆明高端网站制作公司,昆明公租房申请网上登录入口?  建站之星手机一键生成:多端自适应+小程序开发快速建站指南  音响网站制作视频教程,隆霸音响官方网站?  Avalonia如何实现跨窗口通信 Avalonia窗口间数据传递  如何在万网主机上快速搭建网站?  高端云建站费用究竟需要多少预算?  娃派WAP自助建站:免费模板+移动优化,快速打造专业网站  如何选择高效稳定的ISP建站解决方案?  如何破解联通资金短缺导致的基站建设难题?  电商网站制作价格怎么算,网上拍卖流程以及规则?  上海网站制作开发公司,上海买房比较好的网站有哪些?  小说建站VPS选用指南:性能对比、配置优化与建站方案解析  logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?  小型网站制作HTML,*游戏网站怎么搭建?  如何选择适合PHP云建站的开源框架?  网站制作新手教程,新手建设一个网站需要注意些什么?  南阳网站制作公司推荐,小学电子版试卷去哪里找资源好?  移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?  建站主机系统SEO优化与智能配置核心关键词操作指南  武汉网站制作费用多少,在武汉武昌,建面100平方左右的房子,想装暖气片,费用大概是多少啊?  如何高效利用200m空间完成建站?  广德云建站网站建设方案与建站流程优化指南  建站之星如何一键生成手机站?  内部网站制作流程,如何建立公司内部网站?  西安专业网站制作公司有哪些,陕西省建行官方网站?  网站制作的步骤包括,正确网址格式怎么写?  北京营销型网站制作公司,可以用python做一个营销推广网站吗?  如何用搬瓦工VPS快速搭建个人网站?  建站之星导航菜单设置与功能模块配置全攻略  制作表格网站有哪些,线上表格怎么弄?  设计网站制作公司有哪些,制作网页教程?  建站ABC备案流程中有哪些关键注意事项?  建站之星安全性能如何?防护体系能否抵御黑客入侵?  魔方云NAT建站如何实现端口转发?  建站主机选哪种环境更利于SEO优化?  网站制作模板下载什么软件,ppt模板免费下载网站?  如何通过云梦建站系统实现SEO快速优化?  如何在Windows虚拟主机上快速搭建网站?  网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?  建站之星安装失败:服务器环境不兼容?  盘锦网站制作公司,盘锦大洼有多少5G网站?  微信推文制作网站有哪些,怎么做微信推文,急?  如何通过商城自助建站源码实现零基础高效建站?  建站之星IIS配置教程:代码生成技巧与站点搭建指南 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。