Android上实现柱状图表

Android上实现柱状图算法实现

第一步:

获取Android设备的屏幕大小

第二步:

在View对象中使用Canvas绘制蓝色边框与白色背景XY轴两条线,代码如下

第三步:

绘制柱状图标题

第四步:

根据数据集计算出每个系列数据所占X轴的大小,来绘制X 数据名称

第五步:

根据数据集计算出数据单元大小,并将数据单元映射为像素单元,绘制出标尺单位与

背景虚线

第六步:

根据数据集的值来计算出柱状图的高度,以及柱状图的宽度大小,映射为像素值以后

完成绘制。

程序效果图:


技术点详解:

在View中获取Android设备屏幕大小的方法为:

  1. // get default screen size from system service 
  2. WindowManager wm = (WindowManager) this.getContext().getSystemService(Context.WINDOW_SERVICE); 
  3. Display display = wm.getDefaultDisplay(); 
  4. int width = display.getWidth(); 
// 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设备屏幕大小的方法为:

  1. DisplayMetrics displaymetrics = new DisplayMetrics(); 
  2. getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); 
  3. int height = displaymetrics.heightPixels; 
  4. int wwidth = displaymetrics.widthPixels; 
 DisplayMetrics displaymetrics = new DisplayMetrics();
 getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
 int height = displaymetrics.heightPixels;
 int wwidth = displaymetrics.widthPixels;
计算X轴中每个系列所占大小的代码为:

  1. int count = series.getSeriesCount(); 
  2. int xUnit = (width - 2 - xOffset)/count; 
int count = series.getSeriesCount();
int xUnit = (width - 2 - xOffset)/count;
其中xOffset, yOffset值计算公式如下:

  1. int xOffset = (int)(width * 0.1); 
  2. int yOffset = (int)(height * 0.1); 
int xOffset = (int)(width * 0.1);
int yOffset = (int)(height * 0.1);
计算每个系类中,每个柱状图之间缝隙大小的为:

  1. int barWidth = (int)(xUnit/Math.pow(itemList.size(),2)); 
  2. int startPos = xOffset + 2 + xPadding + xUnit*i; 
  3. int interval = barWidth/2
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.使用反锯齿功能,让图形看上去更柔和,启用反锯齿功能的代码为:

  1. myPaint.setAntiAlias(true); 
myPaint.setAntiAlias(true);
3.当要填充一个矩形时候设置Paint的Style

  1. myPaint.setStyle(Style.FILL); 
myPaint.setStyle(Style.FILL);
当要绘制一个边框矩形时候设置Paint的Style

  1. myPaint.setStyle(Style.STROKE); 
myPaint.setStyle(Style.STROKE);
4.如何绘制虚线(dotted line, dash line),使用DashPathEffect对象

本文中的实现代码如下:

  1. myPaint.setStyle(Style.STROKE); 
  2. myPaint.setStrokeWidth(1); 
  3. myPaint.setColor(Color.LTGRAY); 
  4. myPaint.setPathEffect(new DashPathEffect(new float[] {1,3}, 0)); 
myPaint.setStyle(Style.STROKE);
myPaint.setStrokeWidth(1);
myPaint.setColor(Color.LTGRAY);
myPaint.setPathEffect(new DashPathEffect(new float[] {1,3}, 0));

相关的Class说明:

DataSeries对象用来构造数据集,根据key来得到对应的数据系列。源代码如下:

  1. package com.gloomyfish; 
  2.  
  3. import java.util.HashMap; 
  4. import java.util.List; 
  5.  
  6. public class DataSeries { 
  7.     private HashMap<String, List<DataElement>> map; 
  8.      
  9.     public DataSeries() { 
  10.         map = new HashMap<String, List<DataElement>>(); 
  11.     } 
  12.      
  13.     public void addSeries(String key, List<DataElement> itemList) { 
  14.         map.put(key, itemList); 
  15.     } 
  16.      
  17.     public List<DataElement> getItems(String key) { 
  18.         return map.get(key); 
  19.     } 
  20.      
  21.     public int getSeriesCount() { 
  22.         return map.size(); 
  23.     } 
  24.      
  25.     public String[] getSeriesKeys() { 
  26.         return map.keySet().toArray(new String[0]); 
  27.     } 
  28.  
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数据元素,属性有数据名称,值大小,显示颜色等,源代码如下:

  1. package com.gloomyfish; 
  2.  
  3. public class DataElement { 
  4.      
  5.     public DataElement(String name, float value, int color) { 
  6.         this.itemName = name; 
  7.         this.value = value; 
  8.         this.color = color; 
  9.     } 
  10.     public String getItemName() { 
  11.         return itemName; 
  12.     } 
  13.     public void setItemName(String itemName) { 
  14.         this.itemName = itemName; 
  15.     } 
  16.     public float getValue() { 
  17.         return value; 
  18.     } 
  19.     public void setValue(float value) { 
  20.         this.value = value; 
  21.     } 
  22.      
  23.     public void setColor(int color) { 
  24.         this.color = color; 
  25.     } 
  26.      
  27.     public int getColor() { 
  28.         return this.color; 
  29.     } 
  30.      
  31.     private String itemName; 
  32.     private int color; 
  33.     private float value; 
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使用。源代码如下:

  1. package com.gloomyfish; 
  2.  
  3. import java.text.NumberFormat; 
  4. import java.util.ArrayList; 
  5. import java.util.List; 
  6.  
  7. import android.content.Context; 
  8. import android.graphics.Canvas; 
  9. import android.graphics.Color; 
  10. import android.graphics.DashPathEffect; 
  11. import android.graphics.Paint; 
  12. import android.graphics.Paint.Style; 
  13. import android.view.Display; 
  14. import android.view.View; 
  15. import android.view.WindowManager; 
  16.  
  17. public class BarChartPanel extends  View{ 
  18.      
  19.     private String plotTitle; 
  20.     private DataSeries series; 
  21.     public final static int[] platterTable = new int[]{Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.CYAN}; 
  22.     public BarChartPanel(Context context, String plotTitle) { 
  23.         this(context); 
  24.         this.plotTitle = plotTitle; 
  25.     } 
  26.      
  27.     public BarChartPanel(Context context) { 
  28.         super(context); 
  29.     } 
  30.      
  31.     public void setSeries(DataSeries series) { 
  32.         this.series = series; 
  33.     } 
  34.      
  35.     @Override   
  36.     public void onDraw(Canvas canvas) {  
  37.          
  38.         // get default screen size from system service 
  39.         WindowManager wm = (WindowManager) this.getContext().getSystemService(Context.WINDOW_SERVICE); 
  40.         Display display = wm.getDefaultDisplay(); 
  41.         int width = display.getWidth(); 
  42.          
  43.         // remove application title height 
  44.         int height = display.getHeight() - 80;  
  45.         System.out.println("width = " + width); 
  46.         System.out.println("height = " + height); 
  47.          
  48.         // draw background 
  49.         Paint myPaint = new Paint(); 
  50.         myPaint.setColor(Color.BLUE); 
  51.         myPaint.setStrokeWidth(2); 
  52.         canvas.drawRect(0, 0, width, height, myPaint); 
  53.         myPaint.setColor(Color.WHITE); 
  54.         myPaint.setStrokeWidth(0); 
  55.         canvas.drawRect(2, 2, width-2, height-2, myPaint); 
  56.          
  57.         // draw XY Axis 
  58.         int xOffset = (int)(width * 0.1); 
  59.         int yOffset = (int)(height * 0.1); 
  60.         System.out.println("xOffset = " + xOffset); 
  61.          
  62.         myPaint.setColor(Color.BLACK); 
  63.         myPaint.setStrokeWidth(2); 
  64.         canvas.drawLine(2+xOffset, height-2-yOffset, 2+xOffset, 2, myPaint); 
  65.         canvas.drawLine(2+xOffset, height-2-yOffset, width-2, height-2-yOffset, myPaint); 
  66.          
  67.         // draw text title 
  68.         myPaint.setAntiAlias(true); 
  69.         myPaint.setStyle(Style.FILL); 
  70.         canvas.drawText(plotTitle, (width-2)/4, 30, myPaint); 
  71.          
  72.         // draw data series now...... 
  73.         if(series == null) { 
  74.             getMockUpSeries(); 
  75.         } 
  76.         int xPadding = 10
  77.         if(series != null) { 
  78.         int count = series.getSeriesCount(); 
  79.         int xUnit = (width - 2 - xOffset)/count; 
  80.             String[] seriesNames = series.getSeriesKeys(); 
  81.             for(int i=0; i<seriesNames.length; i++) { 
  82.                 canvas.drawText(seriesNames[i], xOffset + 2 + xPadding + xUnit*i, height-yOffset + 10, myPaint); 
  83.             } 
  84.              
  85.             // Y Axis markers 
  86.             float min = 0, max = 0
  87.             for(int i=0; i<seriesNames.length; i++) { 
  88.                 List<DataElement> itemList = series.getItems(seriesNames[i]); 
  89.                 if(itemList != null && itemList.size() > 0) { 
  90.                     for(DataElement item : itemList) { 
  91.                         if(item.getValue() > max) { 
  92.                             max = item.getValue(); 
  93.                         } 
  94.                         if(item.getValue() < min) { 
  95.                             min = item.getValue(); 
  96.                         } 
  97.                     } 
  98.                 } 
  99.             } 
  100.              
  101.             int yUnit = 22;  
  102.             int unitValue = (height-2-yOffset)/yUnit; 
  103.             myPaint.setStyle(Style.STROKE); 
  104.             myPaint.setStrokeWidth(1); 
  105.             myPaint.setColor(Color.LTGRAY); 
  106.             myPaint.setPathEffect(new DashPathEffect(new float[] {1,3}, 0)); 
  107.             float ymarkers = (max-min)/yUnit; 
  108.             NumberFormat nf = NumberFormat.getInstance(); 
  109.             nf.setMinimumFractionDigits(2); 
  110.             nf.setMaximumFractionDigits(2); 
  111.             for(int i=0; i<20; i++) { 
  112.                 canvas.drawLine(2+xOffset, height-2-yOffset - (unitValue * (i+1)), width-2, height-2-yOffset - (unitValue * (i+1)), myPaint); 
  113.             } 
  114.              
  115.             // clear the path effect 
  116.             myPaint.setColor(Color.BLACK); 
  117.             myPaint.setStyle(Style.STROKE); 
  118.             myPaint.setStrokeWidth(0); 
  119.             myPaint.setPathEffect(null);  
  120.             for(int i=0; i<20; i++) { 
  121.                 float markValue = ymarkers * (i+1); 
  122.                 canvas.drawText(nf.format(markValue), 3, height-2-yOffset - (unitValue * (i+1)), myPaint); 
  123.             } 
  124.              
  125.             // draw bar chart now 
  126.             myPaint.setStyle(Style.FILL); 
  127.             myPaint.setStrokeWidth(0); 
  128.             String maxItemsKey = null
  129.             int maxItem = 0
  130.             for(int i=0; i<seriesNames.length; i++) { 
  131.                 List<DataElement> itemList = series.getItems(seriesNames[i]); 
  132.                 int barWidth = (int)(xUnit/Math.pow(itemList.size(),2)); 
  133.                 int startPos = xOffset + 2 + xPadding + xUnit*i; 
  134.                 int index = 0
  135.                 int interval = barWidth/2
  136.                 if(itemList.size() > maxItem) { 
  137.                     maxItemsKey = seriesNames[i]; 
  138.                     maxItem = itemList.size(); 
  139.                 } 
  140.                 for(DataElement item : itemList) { 
  141.                     myPaint.setColor(item.getColor()); 
  142.                     int barHeight = (int)((item.getValue()/ymarkers) * unitValue); 
  143.                     canvas.drawRect(startPos + barWidth*index + interval*index, height-2-yOffset-barHeight,  
  144.                             startPos + barWidth*index + interval*index + barWidth, height-2-yOffset, myPaint); 
  145.                     index++; 
  146.                 } 
  147.             } 
  148.              
  149.             List<DataElement> maxItemList = series.getItems(maxItemsKey); 
  150.             int itemIndex = 0
  151.             int basePos = 10
  152.             for(DataElement item : maxItemList) { 
  153.                 myPaint.setColor(item.getColor()); 
  154.                 canvas.drawRect(basePos + itemIndex * 10, height-yOffset + 15, basePos + itemIndex * 10 + 10, height-yOffset + 30, myPaint); 
  155.                 myPaint.setColor(Color.BLACK); 
  156.                 canvas.drawText(item.getItemName(), basePos + (itemIndex+1) * 10, height-yOffset + 25, myPaint); 
  157.                 itemIndex++; 
  158.                 basePos = basePos + xUnit*itemIndex; 
  159.             } 
  160.         } 
  161.     } 
  162.      
  163.      
  164.     public DataSeries getMockUpSeries() { 
  165.         series = new DataSeries(); 
  166.         List<DataElement> itemListOne = new ArrayList<DataElement>(); 
  167.         itemListOne.add(new DataElement("shoes",120.0f, platterTable[0])); 
  168.         itemListOne.add(new DataElement("jacket",100.0f, platterTable[1])); 
  169.         series.addSeries("First Quarter", itemListOne); 
  170.          
  171.         List<DataElement> itemListTwo = new ArrayList<DataElement>(); 
  172.         itemListTwo.add(new DataElement("shoes",110.0f, platterTable[0])); 
  173.         itemListTwo.add(new DataElement("jacket",50.0f, platterTable[1])); 
  174.         series.addSeries("Second Quarter", itemListTwo); 
  175.          
  176.         List<DataElement> itemListThree = new ArrayList<DataElement>(); 
  177.         itemListThree.add(new DataElement("shoes",100.0f, platterTable[0])); 
  178.         itemListThree.add(new DataElement("jacket",280.0f, platterTable[1])); 
  179.         series.addSeries("Third Quarter", itemListThree); 
  180.          
  181.         List<DataElement> itemListFour = new ArrayList<DataElement>(); 
  182.         itemListFour.add(new DataElement("shoes",120.0f, platterTable[0])); 
  183.         itemListFour.add(new DataElement("jacket",100.0f, platterTable[1])); 
  184.         series.addSeries("Fourth Quarter", itemListFour); 
  185.         return series; 
  186.     } 
  187.  
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启动类。

  1. package com.gloomyfish; 
  2.  
  3. import android.app.Activity; 
  4. import android.os.Bundle; 
  5.  
  6. public class BarChartDemoActivity extends Activity { 
  7.     /** Called when the activity is first created. */ 
  8.     @Override 
  9.     public void onCreate(Bundle savedInstanceState) { 
  10.         super.onCreate(savedInstanceState); 
  11.         setContentView(new BarChartPanel(this, "Quarter Vs. sales volume")); 
  12.     } 
  13.  

 

转自:http://blog.csdn.net/jia20003/article/details/7522716

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值