欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android编程实现canvas绘制柱状统计图功能【自动计算宽高及分度值、可左右滑动】

程序员文章站 2024-02-15 08:51:04
本文实例讲述了android编程实现canvas绘制柱状统计图功能。分享给大家供大家参考,具体如下: 这里实现了一个简单的柱状统计图,如下:   特点:...

本文实例讲述了android编程实现canvas绘制柱状统计图功能。分享给大家供大家参考,具体如下:

这里实现了一个简单的柱状统计图,如下:

Android编程实现canvas绘制柱状统计图功能【自动计算宽高及分度值、可左右滑动】 Android编程实现canvas绘制柱状统计图功能【自动计算宽高及分度值、可左右滑动】

特点:

1.根据数据源自动计算每个条目的高度、宽度、间距,自动计算分度值。

2.当条目数较多时,可左右滑动查看全部内容,图形、文字同步滑动,并且松手后会渐渐的停下来(而不是立刻停下来)。

代码:

(1)核心代码:barchartview.java

package com.sina.appbarchart;
import android.app.activity;
import android.content.context;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.path;
import android.graphics.rect;
import android.support.annotation.nonnull;
import android.support.v7.app.actionbar;
import android.support.v7.app.actionbaractivity;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;
/**
 * 自定义组件:条形统计图
 * created by hanj on 14-12-30.
 */
public class barchartview extends view {
 private int screenw, screenh;
 private barchartitembean[] mitems;
 //max value in mitems.
 private float maxvalue;
 //max height of the bar
 private int maxheight;
 private int[] mbarcolors = new int[]{color.red, color.green, color.blue, color.yellow, color.magenta, color.cyan};
 private paint barpaint, linepaint, textpaint;
 private rect barrect, leftwhiterect, rightwhiterect;
 private path textpath;
 private int leftmargin, topmargin, smallmargin;
 //the width of one bar item
 private int baritemwidth;
 //the spacing between two bar items.
 private int barspace;
 //the width of the line.
 private int linestrokewidth;
 /**
  * the x-position of y-index and the y-position of the x-index..
  */
 private float x_index_starty, y_index_startx;
 private bitmap arrowbmp;
 private rect x_index_arrowrect, y_index_arrowrect;
 private static final int bg_color = color.parsecolor("#e5e5e5");
 public barchartview(context context, attributeset attrs) {
  super(context, attrs);
  init(context);
 }
 private void init(context context) {
  screenw = screenutils.getscreenw(context);
  screenh = screenutils.getscreenh(context);
  leftmargin = screenutils.dp2px(context, 16);
  topmargin = screenutils.dp2px(context, 40);
  smallmargin = screenutils.dp2px(context, 6);
  barpaint = new paint();
  barpaint.setcolor(mbarcolors[0]);
  linepaint = new paint();
  linestrokewidth = screenutils.dp2px(context, 1);
  linepaint.setstrokewidth(linestrokewidth);
  textpaint = new paint();
  textpaint.setantialias(true);
  barrect = new rect(0, 0, 0, 0);
  textpath = new path();
  leftwhiterect = new rect(0, 0, 0, screenh);
  rightwhiterect = new rect(screenw - leftmargin, 0, screenw, screenh);
  arrowbmp = bitmapfactory.decoderesource(context.getresources(), r.drawable.arrow_up);
 }
 //标记是否已经获取过状态拉的高度
 private boolean statusheighthasget;
 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  if (!statusheighthasget) {
   substatusbarheight();
   statusheighthasget = true;
  }
  //draw background
  canvas.drawcolor(bg_color);
  //bounds
  checkleftmoving();
  textpaint.settextsize(screenutils.dp2px(getcontext(), 16));
  for (int i = 0; i < mitems.length; i++) {
   //draw bar rect
   barrect.left = (int) y_index_startx + baritemwidth * i + barspace * (i + 1) - (int) leftmoving;
   barrect.top = topmargin * 2 + (int) (maxheight * (1.0f - mitems[i].itemvalue / maxvalue));
   barrect.right = barrect.left + baritemwidth;
   barpaint.setcolor(mbarcolors[i % mbarcolors.length]);
   canvas.drawrect(barrect, barpaint);
   //draw type text
   string typetext = mitems[i].itemtype;
   float textpathstartx = barrect.left + baritemwidth / 2 -
     (float) (math.sin(math.pi / 6)) * textpaint.measuretext("好") / 2;
   float textpathstarty = barrect.bottom;
   textpath.reset();
   textpath.moveto(textpathstartx, textpathstarty);
   textpath.lineto(textpathstartx + (float) (1000 * math.tan(math.pi / 6)), textpathstarty + 1000);
   canvas.drawtextonpath(typetext, textpath, smallmargin * 1.5f, smallmargin * 2, textpaint);
   //draw value text
   string valuetext = string.valueof(mitems[i].itemvalue);
   canvas.drawtext(valuetext, barrect.left - (textpaint.measuretext(valuetext) - baritemwidth) / 2,
     barrect.top - smallmargin, textpaint);
  }
  //draw left white space and right white space
  int c = barpaint.getcolor();
  barpaint.setcolor(bg_color);
  leftwhiterect.right = (int) y_index_startx;
  canvas.drawrect(leftwhiterect, barpaint);
  canvas.drawrect(rightwhiterect, barpaint);
  barpaint.setcolor(c);
  //draw x-index line.
  canvas.drawline(
    y_index_startx - linestrokewidth / 2,
    x_index_starty,
    screenw - leftmargin,
    x_index_starty,
    linepaint);
  //draw y-index line.
  canvas.drawline(
    y_index_startx,
    x_index_starty + linestrokewidth / 2,
    y_index_startx,
    topmargin / 2,
    linepaint);
  canvas.drawbitmap(arrowbmp, null, y_index_arrowrect, null);
  canvas.save();
  canvas.rotate(90, (x_index_arrowrect.left + x_index_arrowrect.right) / 2, (x_index_arrowrect.top + x_index_arrowrect.bottom) / 2);
  canvas.drawbitmap(arrowbmp, null, x_index_arrowrect, null);
  canvas.restore();
  //draw division value
  int maxdivisionvalueheight = (int) (maxheight * 1.0f / maxvalue * maxdivisionvalue);
  textpaint.settextsize(screenutils.dp2px(getcontext(), 10));
  for (int i = 1; i <= 10; i++) {
   float starty = barrect.bottom - maxdivisionvalueheight * 0.1f * i;
   if (starty < topmargin / 2) {
    break;
   }
   canvas.drawline(y_index_startx, starty, y_index_startx + 10, starty, linepaint);
   string text = string.valueof(maxdivisionvalue * 0.1f * i);
   canvas.drawtext(text,
     y_index_startx - textpaint.measuretext(text) - 5,
     starty + textpaint.measuretext("0") / 2,
     textpaint);
  }
 }
 private float leftmoving;
 private float lastpointx;
 private float movingleftthistime = 0.0f;
 @override
 public boolean ontouchevent(@nonnull motionevent event) {
  int type = event.getaction();
  switch (type) {
   case motionevent.action_down:
    lastpointx = event.getrawx();
    break;
   case motionevent.action_move:
    float x = event.getrawx();
    movingleftthistime = lastpointx - x;
    leftmoving += movingleftthistime;
    lastpointx = x;
    invalidate();
    break;
   case motionevent.action_up:
    //smooth scroll
    new thread(new smoothscrollthread(movingleftthistime)).start();
    break;
   default:
    return super.ontouchevent(event);
  }
  return true;
 }
 /**
  * check the value of leftmoving to ensure that the view is not out of the screen.
  */
 private void checkleftmoving() {
  if (leftmoving < 0) {
   leftmoving = 0;
  }
  if (leftmoving > (maxright - minright)) {
   leftmoving = maxright - minright;
  }
 }
 public barchartitembean[] getitems() {
  return mitems;
 }
 public void setitems(barchartitembean[] items) {
  if (items == null) {
   throw new runtimeexception("barchartview.setitems(): the param items cannot be null.");
  }
  if (items.length == 0) {
   return;
  }
  this.mitems = items;
  //calculate the max value.
  maxvalue = items[0].itemvalue;
  for (barchartitembean bean : items) {
   if (bean.itemvalue > maxvalue) {
    maxvalue = bean.itemvalue;
   }
  }
  //calculate the max division value.
  getrange(maxvalue, 0);
  //get the width of each bar.
  getbaritemwidth(screenw, items.length);
  //refresh the view.
  invalidate();
 }
 private int maxright, minright;
 /**
  * get the width of each bar which is depended on the screenw and item count.
  */
 private void getbaritemwidth(int screenw, int itemcount) {
  //the min width of the bar is 50dp.
  int minbarwidth = screenutils.dp2px(getcontext(), 40);
  //the min width of spacing.
  int minbarspacing = screenutils.dp2px(getcontext(), 30);
  baritemwidth = (screenw - leftmargin * 2) / (itemcount + 3);
  barspace = (screenw - leftmargin * 2 - baritemwidth * itemcount) / (itemcount + 1);
  if (baritemwidth < minbarwidth || barspace < minbarspacing) {
   baritemwidth = minbarwidth;
   barspace = minbarspacing;
  }
  maxright = (int) y_index_startx + linestrokewidth + (barspace + baritemwidth) * mitems.length;
  minright = screenw - leftmargin - barspace;
 }
 /**
  * sub the height of status bar and action bar to get the accurate height of screen.
  */
 private void substatusbarheight() {
  //the height of the status bar
  int statusheight = screenutils.getstatusbarheight((activity) getcontext());
  //the height of the actionbar
  actionbar ab = ((actionbaractivity) getcontext()).getsupportactionbar();
  int abheight = ab == null ? 0 : ab.getheight();
  screenh -= (statusheight + abheight);
  barrect.top = topmargin * 2;
  barrect.bottom = screenh - topmargin * 3;
  maxheight = barrect.bottom - barrect.top;
  x_index_starty = barrect.bottom;
  x_index_arrowrect = new rect(screenw - leftmargin, (int) (x_index_starty - 10),
    screenw - leftmargin + 10, (int) (x_index_starty + 10));
 }
 //the max and min division value.
 private float maxdivisionvalue, mindivisionvalue;
 //get the max and min division value by the max and min value in mitems.
 private void getrange(float maxvalue, float minvalue) {
  //max
  int scale = utility.getscale(maxvalue);
  float unscaledvalue = (float) (maxvalue / math.pow(10, scale));
  maxdivisionvalue = (float) (getrangetop(unscaledvalue) * math.pow(10, scale));
  y_index_startx = getdivisiontextmaxwidth(maxdivisionvalue) + 10;
  y_index_arrowrect = new rect((int) (y_index_startx - 5), topmargin / 2 - 20,
    (int) (y_index_startx + 5), topmargin / 2);
 }
 private float getrangetop(float value) {
  //value: [1,10)
  if (value < 1.2) {
   return 1.2f;
  }
  if (value < 1.5) {
   return 1.5f;
  }
  if (value < 2.0) {
   return 2.0f;
  }
  if (value < 3.0) {
   return 3.0f;
  }
  if (value < 4.0) {
   return 4.0f;
  }
  if (value < 5.0) {
   return 5.0f;
  }
  if (value < 6.0) {
   return 6.0f;
  }
  if (value < 8.0) {
   return 8.0f;
  }
  return 10.0f;
 }
 /**
  * get the max width of the division value text.
  */
 private float getdivisiontextmaxwidth(float maxdivisionvalue) {
  paint textpaint = new paint();
  textpaint.settextsize(screenutils.dp2px(getcontext(), 10));
  float max = textpaint.measuretext(string.valueof(maxdivisionvalue * 0.1f));
  for (int i = 2; i <= 10; i++) {
   float w = textpaint.measuretext(string.valueof(maxdivisionvalue * 0.1f * i));
   if (w > max) {
    max = w;
   }
  }
  return max;
 }
 /**
  * use this thread to create a smooth scroll after action_up.
  */
 private class smoothscrollthread implements runnable {
  float lastmoving;
  boolean scrolling = true;
  private smoothscrollthread(float lastmoving) {
   this.lastmoving = lastmoving;
   scrolling = true;
  }
  @override
  public void run() {
   while (scrolling) {
    long start = system.currenttimemillis();
    lastmoving = (int) (0.9f * lastmoving);
    leftmoving += lastmoving;
    checkleftmoving();
    postinvalidate();
    if (math.abs(lastmoving) < 5) {
     scrolling = false;
    }
    long end = system.currenttimemillis();
    if (end - start < 20) {
     try {
      thread.sleep(20 - (end - start));
     } catch (interruptedexception e) {
      e.printstacktrace();
     }
    }
   }
  }
 }
 /**
  * a model class to keep the bar item info.
  */
 static class barchartitembean {
  private string itemtype;
  private float itemvalue;
  public barchartitembean(string itemtype, float itemvalue) {
   this.itemtype = itemtype;
   this.itemvalue = itemvalue;
  }
 }
}

(2)该自定义组件的使用:

package com.sina.appbarchart;
import android.support.v7.app.actionbaractivity;
import android.os.bundle;
public class mainactivity extends actionbaractivity {
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  barchartview barchartview = (barchartview) findviewbyid(r.id.bar_chart);
  barchartview.barchartitembean[] items = new barchartview.barchartitembean[]{
    new barchartview.barchartitembean("餐饮", 300),
    new barchartview.barchartitembean("学习", 200),
    new barchartview.barchartitembean("旅行", 270),
    new barchartview.barchartitembean("购物", 110),
    new barchartview.barchartitembean("人际关系", 120),
    new barchartview.barchartitembean("娱乐", 80),
    new barchartview.barchartitembean("投资", 110),
    new barchartview.barchartitembean("教育", 280)
  };
  barchartview.setitems(items);
 }
}

完整实例代码点击此处本站下载

更多关于android相关内容感兴趣的读者可查看本站专题:《android图形与图像处理技巧总结》、《android开发入门与进阶教程》、《android调试技巧与常见问题解决方法汇总》、《android基本组件用法总结》、《android视图view技巧总结》、《android布局layout技巧总结》及《android控件用法总结

希望本文所述对大家android程序设计有所帮助。