当前位置: 移动技术网 > IT编程>移动开发>Android > Android自定义View——扇形统计图的实现代码

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

幽灵幻影 卡尔萨斯,现在油价多少钱一升,511网盘

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下载地址:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网