Android上實現柱狀圖表

jopen 11年前發布 | 36K 次閱讀 Android Android開發 移動開發

Android上實現柱狀圖算法實現

第一步:

獲取Android設備的屏幕大小

第二步:

在View對象中使用Canvas繪制藍色邊框與白色背景XY軸兩條線,代碼如下

第三步:

繪制柱狀圖標題

第四步:

根據數據集計算出每個系列數據所占X軸的大小,來繪制X 數據名稱

第五步:

根據數據集計算出數據單元大小,并將數據單元映射為像素單元,繪制出標尺單位與

背景虛線

第六步:

根據數據集的值來計算出柱狀圖的高度,以及柱狀圖的寬度大小,映射為像素值以后

完成繪制。

程序效果圖:

1335700297_2087.png

技術點詳解:

在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"));
    }

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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!