Android上实现柱状图算法实现
第一步:
获取Android设备的屏幕大小
第二步:
在View对象中使用Canvas绘制蓝色边框与白色背景XY轴两条线,代码如下
第三步:
绘制柱状图标题
第四步:
根据数据集计算出每个系列数据所占X轴的大小,来绘制X 数据名称
第五步:
根据数据集计算出数据单元大小,并将数据单元映射为像素单元,绘制出标尺单位与
背景虚线
第六步:
根据数据集的值来计算出柱状图的高度,以及柱状图的宽度大小,映射为像素值以后
完成绘制。
程序效果图:
技术点详解:
在View中获取Android设备屏幕大小的方法为:
// get default screen size from system service
WindowManager wm = (WindowManager) this.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int width = display.getWidth();
在Activity中获取Android设备屏幕大小的方法为:
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int wwidth = displaymetrics.widthPixels;
计算X轴中每个系列所占大小的代码为:
int count = series.getSeriesCount();
int xUnit = (width - 2 - xOffset)/count;
其中xOffset, yOffset值计算公式如下:
int xOffset = (int)(width * 0.1);
int yOffset = (int)(height * 0.1);
计算每个系类中,每个柱状图之间缝隙大小的为:
int barWidth = (int)(xUnit/Math.pow(itemList.size(),2));
int startPos = xOffset + 2 + xPadding + xUnit*i;
int interval = barWidth/2;
其中barWidth表示每个柱状矩形的宽度,interval表示同一数据系列中表示
每个矩形之间的间隔。
另外一些技巧:
1.在起始位置填充额外的长度大小,让柱状图不会紧贴Y轴,看上去更美观
默认的xPadding值等于10,int xPadding = 10;
2.使用反锯齿功能,让图形看上去更柔和,启用反锯齿功能的代码为:
myPaint.setAntiAlias(true);
3.当要填充一个矩形时候设置Paint的Style
myPaint.setStyle(Style.FILL);
当要绘制一个边框矩形时候设置Paint的Style
myPaint.setStyle(Style.STROKE);
4.如何绘制虚线(dotted line, dash line),使用DashPathEffect对象
本文中的实现代码如下:
myPaint.setStyle(Style.STROKE);
myPaint.setStrokeWidth(1);
myPaint.setColor(Color.LTGRAY);
myPaint.setPathEffect(new DashPathEffect(new float[] {1,3}, 0));
相关的Class说明:
DataSeries对象用来构造数据集,根据key来得到对应的数据系列。源代码如下:
package com.gloomyfish;
import java.util.HashMap;
import java.util.List;
public class DataSeries {
private HashMap<String, List<DataElement>> map;
public DataSeries() {
map = new HashMap<String, List<DataElement>>();
}
public void addSeries(String key, List<DataElement> itemList) {
map.put(key, itemList);
}
public List<DataElement> getItems(String key) {
return map.get(key);
}
public int getSeriesCount() {
return map.size();
}
public String[] getSeriesKeys() {
return map.keySet().toArray(new String[0]);
}
}
DataElement数据元素,属性有数据名称,值大小,显示颜色等,源代码如下:
package com.gloomyfish;
public class DataElement {
public DataElement(String name, float value, int color) {
this.itemName = name;
this.value = value;
this.color = color;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public float getValue() {
return value;
}
public void setValue(float value) {
this.value = value;
}
public void setColor(int color) {
this.color = color;
}
public int getColor() {
return this.color;
}
private String itemName;
private int color;
private float value;
}
BarChartPanel独立的组件,继承自Android View对象,是柱状图的图形组件,可以为
任何版本的Android使用。源代码如下:
package com.gloomyfish;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
public class BarChartPanel extends View{
private String plotTitle;
private DataSeries series;
public final static int[] platterTable = new int[]{Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.CYAN};
public BarChartPanel(Context context, String plotTitle) {
this(context);
this.plotTitle = plotTitle;
}
public BarChartPanel(Context context) {
super(context);
}
public void setSeries(DataSeries series) {
this.series = series;
}
@Override
public void onDraw(Canvas canvas) {
// get default screen size from system service
WindowManager wm = (WindowManager) this.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int width = display.getWidth();
// remove application title height
int height = display.getHeight() - 80;
System.out.println("width = " + width);
System.out.println("height = " + height);
// draw background
Paint myPaint = new Paint();
myPaint.setColor(Color.BLUE);
myPaint.setStrokeWidth(2);
canvas.drawRect(0, 0, width, height, myPaint);
myPaint.setColor(Color.WHITE);
myPaint.setStrokeWidth(0);
canvas.drawRect(2, 2, width-2, height-2, myPaint);
// draw XY Axis
int xOffset = (int)(width * 0.1);
int yOffset = (int)(height * 0.1);
System.out.println("xOffset = " + xOffset);
myPaint.setColor(Color.BLACK);
myPaint.setStrokeWidth(2);
canvas.drawLine(2+xOffset, height-2-yOffset, 2+xOffset, 2, myPaint);
canvas.drawLine(2+xOffset, height-2-yOffset, width-2, height-2-yOffset, myPaint);
// draw text title
myPaint.setAntiAlias(true);
myPaint.setStyle(Style.FILL);
canvas.drawText(plotTitle, (width-2)/4, 30, myPaint);
// draw data series now......
if(series == null) {
getMockUpSeries();
}
int xPadding = 10;
if(series != null) {
int count = series.getSeriesCount();
int xUnit = (width - 2 - xOffset)/count;
String[] seriesNames = series.getSeriesKeys();
for(int i=0; i<seriesNames.length; i++) {
canvas.drawText(seriesNames[i], xOffset + 2 + xPadding + xUnit*i, height-yOffset + 10, myPaint);
}
// Y Axis markers
float min = 0, max = 0;
for(int i=0; i<seriesNames.length; i++) {
List<DataElement> itemList = series.getItems(seriesNames[i]);
if(itemList != null && itemList.size() > 0) {
for(DataElement item : itemList) {
if(item.getValue() > max) {
max = item.getValue();
}
if(item.getValue() < min) {
min = item.getValue();
}
}
}
}
int yUnit = 22;
int unitValue = (height-2-yOffset)/yUnit;
myPaint.setStyle(Style.STROKE);
myPaint.setStrokeWidth(1);
myPaint.setColor(Color.LTGRAY);
myPaint.setPathEffect(new DashPathEffect(new float[] {1,3}, 0));
float ymarkers = (max-min)/yUnit;
NumberFormat nf = NumberFormat.getInstance();
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
for(int i=0; i<20; i++) {
canvas.drawLine(2+xOffset, height-2-yOffset - (unitValue * (i+1)), width-2, height-2-yOffset - (unitValue * (i+1)), myPaint);
}
// clear the path effect
myPaint.setColor(Color.BLACK);
myPaint.setStyle(Style.STROKE);
myPaint.setStrokeWidth(0);
myPaint.setPathEffect(null);
for(int i=0; i<20; i++) {
float markValue = ymarkers * (i+1);
canvas.drawText(nf.format(markValue), 3, height-2-yOffset - (unitValue * (i+1)), myPaint);
}
// draw bar chart now
myPaint.setStyle(Style.FILL);
myPaint.setStrokeWidth(0);
String maxItemsKey = null;
int maxItem = 0;
for(int i=0; i<seriesNames.length; i++) {
List<DataElement> itemList = series.getItems(seriesNames[i]);
int barWidth = (int)(xUnit/Math.pow(itemList.size(),2));
int startPos = xOffset + 2 + xPadding + xUnit*i;
int index = 0;
int interval = barWidth/2;
if(itemList.size() > maxItem) {
maxItemsKey = seriesNames[i];
maxItem = itemList.size();
}
for(DataElement item : itemList) {
myPaint.setColor(item.getColor());
int barHeight = (int)((item.getValue()/ymarkers) * unitValue);
canvas.drawRect(startPos + barWidth*index + interval*index, height-2-yOffset-barHeight,
startPos + barWidth*index + interval*index + barWidth, height-2-yOffset, myPaint);
index++;
}
}
List<DataElement> maxItemList = series.getItems(maxItemsKey);
int itemIndex = 0;
int basePos = 10;
for(DataElement item : maxItemList) {
myPaint.setColor(item.getColor());
canvas.drawRect(basePos + itemIndex * 10, height-yOffset + 15, basePos + itemIndex * 10 + 10, height-yOffset + 30, myPaint);
myPaint.setColor(Color.BLACK);
canvas.drawText(item.getItemName(), basePos + (itemIndex+1) * 10, height-yOffset + 25, myPaint);
itemIndex++;
basePos = basePos + xUnit*itemIndex;
}
}
}
public DataSeries getMockUpSeries() {
series = new DataSeries();
List<DataElement> itemListOne = new ArrayList<DataElement>();
itemListOne.add(new DataElement("shoes",120.0f, platterTable[0]));
itemListOne.add(new DataElement("jacket",100.0f, platterTable[1]));
series.addSeries("First Quarter", itemListOne);
List<DataElement> itemListTwo = new ArrayList<DataElement>();
itemListTwo.add(new DataElement("shoes",110.0f, platterTable[0]));
itemListTwo.add(new DataElement("jacket",50.0f, platterTable[1]));
series.addSeries("Second Quarter", itemListTwo);
List<DataElement> itemListThree = new ArrayList<DataElement>();
itemListThree.add(new DataElement("shoes",100.0f, platterTable[0]));
itemListThree.add(new DataElement("jacket",280.0f, platterTable[1]));
series.addSeries("Third Quarter", itemListThree);
List<DataElement> itemListFour = new ArrayList<DataElement>();
itemListFour.add(new DataElement("shoes",120.0f, platterTable[0]));
itemListFour.add(new DataElement("jacket",100.0f, platterTable[1]));
series.addSeries("Fourth Quarter", itemListFour);
return series;
}
}
BarChartDemoActivity测试该组件的Android Activity启动类。
package com.gloomyfish;
import android.app.Activity;
import android.os.Bundle;
public class BarChartDemoActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new BarChartPanel(this, "Quarter Vs. sales volume"));
}
}
转载请务必注明出处
分享到:
相关推荐
android 画图、线性图表、柱状图表、圆弧计分、注释非常详细,屏幕适配已经做好
这个是android动态绘制柱状图图表(Chart)效果,该源码效果主要是采用了canvas实现的,以及效果的主要是开启线程和一些引擎差不多,该效果实现也比较简单的,大家可以研究一下该源码,是一个很不错图表(Chart)的案例...
Android 动态柱状图,在线程里发送消息,来实现动画效果,每个立柱大小不同颜色不同
WilliamChart各种图表效果实现大全,有水平线条表格,有柱状表格等。 由LineFragment,BarFragment,StackedFragment,SandboxFragment几个fragment封装实现几种效果。 DrawerFragment来实现简单框架。并且提供接口 ...
一个炫酷的柱状图表。 Import Step 1. Add the JitPack repository to your build file Add it in your root build.gradle at the end of repositories: allprojects { repositories { ... maven { url '...
一开始是使用第三方的绘图框架Achartengine来绘制,能实现一大部分的图形。可针对公司产品天马行空的想象显然Achartengine已经不能满足现在的项目了。为此小编我只能尝试着自己自定义一些图表类的控件。这里给大家...
android自带的图表控件都很简单,样式单调,这个例子利用html5加js定义图表样式,在html里调用java的方法传递数据生成图表。很强大。同时也是一个对于html调用java方法的很大的启发!
在Android中实现折线图 柱图 饼图的一个示例,需要此需求的可以参考下!
android柱状图 android曲线图 android饼状图 android统计图表
android studio 统计图生成app(柱状图/折线图/饼图/折线柱状结合图)从数据库中读取数据生成统计图
android可拖动柱状图.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
这个是android动态绘制柱状图图表(Chart)效果,该源码效果主要是采用了canvas实现的,以及效果的主要是开启线程和一些引擎差不多,该效果实现也比较简单的,大家可以研究一下该源码,是一个很不错图表(Chart)的案例...
android水平柱状图view,可以用于一些图表统计类的app之中,帮助开发者快速集成
Android制作曲线、柱状图、饼形等图表——使用AChartEngine
1、通过实现recyclerview的ItemDecoration类实现折线图柱状图绘制 2、代码没有做优化及封装,希望给大家能扩展下思路 3、没有使用任何第三方的图表库 4、有什么问题欢迎留言讨论
柱状图是统计图表中经常用到的一种图表,比如降雨量之类的统计展示。这篇文章主要给大家介绍了关于利用Android如何实现简易的柱状图和曲线图表的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下。
Android App开发使用的图表框架,可以在App中轻松实现多种图表。 如:K线图,折线图,柱状图,环形图等等,近20多种
本文将通过示例代码介绍如何自定义简单的直方图表,此图表并非常见的直方图表,而是可以分组的。此文不会过多涉及原理,比较简单,示例图片如下(gif图片没有制作好,有闪烁,请见谅): 对于该示例的代码实现,其实...
Android实现个性化柱状图效果.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
android-charts是一套基于Java和Android开发的图形图表控件. 目前该套图表主要包括以下组件: 网格图(gird chart) 线图(line charts),包含单线图和多线图 柱状图(stick charts),包含基本柱状图和特殊柱状图 支持...