Android编程实现canvas绘制柱状统计图功能【自动计算宽高及分度值、可左右滑动】
程序员文章站
2024-02-15 08:51:04
本文实例讲述了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程序设计有所帮助。