Android上实现柱状图表 可实现边框矩形 没填充色

时间:2021-08-24 18:08:42

Android上实现柱状图算法实现

第一步:

获取Android设备的屏幕大小

第二步:

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

第三步:

绘制柱状图标题

第四步:

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

第五步:

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

背景虚线

第六步:

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

完成绘制。

程序效果图:

Android上实现柱状图表 可实现边框矩形 没填充色

技术点详解:

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

[java] view plaincopy
  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();  
在Activity中获取Android设备屏幕大小的方法为:

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

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

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

[java] view plaincopy
  1. int barWidth = (int)(xUnit/Math.pow(itemList.size(),2));  
  2. int startPos = xOffset + 2 + xPadding + xUnit*i;  
  3. int interval = barWidth/2;  
其中barWidth表示每个柱状矩形的宽度,interval表示同一数据系列中表示

每个矩形之间的间隔。

另外一些技巧:

1.在起始位置填充额外的长度大小,让柱状图不会紧贴Y轴,看上去更美观

默认的xPadding值等于10, int xPadding = 10;

2.使用反锯齿功能,让图形看上去更柔和,启用反锯齿功能的代码为:

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

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

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

本文中的实现代码如下:

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

相关的Class说明:

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

[java] view plaincopy
  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.   
  29. }  
DataElement 数据元素,属性有数据名称,值大小,显示颜色等,源代码如下:

[java] view plaincopy
  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;  
  34. }  
BarChartPanel 独立的组件,继承自Android View对象,是柱状图的图形组件,可以为

任何版本的Android使用。源代码如下:

[java] view plaincopy
  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(00, width, height, myPaint);  
  53.         myPaint.setColor(Color.WHITE);  
  54.         myPaint.setStrokeWidth(0);  
  55.         canvas.drawRect(22, 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)/430, 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.   
  188. }  
BarChartDemoActivity测试该组件的Android Activity启动类。

[java] view plaincopy
  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.   
  14. }  

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