1. 程式人生 > >第三方繪圖控制元件 AChartEngine 淺析

第三方繪圖控制元件 AChartEngine 淺析

背景

當今越來越多的Android APP使用友好的介面與使用者互動,如圖所示的炒股類APP、財務報表類APP等。
炒股類APP的圖形繪製 財務報表類APP的圖形繪製

可見,繪圖控制元件必不可少,Android系統提供瞭如下的繪圖工具:

  • 2D圖形繪製
    -Paint
    -Canvas

  • 3D圖形繪製
    -Open GL ES

系統的繪圖控制元件理論上當然可以繪製出任何圖形效果,但一般來說,開發者不會從頭開發一個圖形介面。下面介紹一個第三方開源繪圖控制元件,通過該控制元件,可以方便地繪製折線圖,柱狀圖,餅圖,散點圖等多種常見的圖形。demo原始碼可通過如下連結下載https://github.com/ddanny/achartengine

,或從我上傳的資源中下載。

AChartEngine

控制元件支援下列圖形(java檔案對應該圖形示例程式):

  • 折線圖
    -AverageTemperatureChart.java
    -TrigonometricFunctionsChart.java
    -MultipleTemperatureChart.java
    -GeneratedChartDemo.java

  • 立方折線圖
    -AverageCubicTemperatureChart.java

  • 條形圖/柱狀圖
    -SalesStackedBarChart.java
    -SalesBarChart.java
    -GeneratedChartDemo.java

  • 範圍條形圖/柱狀圖
    -TemperatureChart.java

  • 散點圖
    -TemperatureChart.java
    -GeneratedChartDemo.java

  • 面積圖
    -GeneratedChartDemo.java

  • 時間圖
    -ProjectStatusChart.java
    -SalesGrowthChart.java
    -GeneratedChartDemo.java

  • 餅圖
    -BudgetPieChart.java

  • 圓環圖
    -BudgetDoughnutChart.java

  • 氣泡圖
    -ProjectStatusBubbleChart.java

  • 撥號盤/壓力錶
    -WeightDialChart.java

  • 組合圖
    -CombinedTemperatureChart.java

先看看該Demo的部分執行效果,圖1示例了折線圖的效果,圖2示例了柱狀圖的效果,圖3示例了拋物線的效果,圖4是散點圖,圖5是餅圖的效果,圖6是權重圖效果。。。

折線圖 柱狀圖
拋物線 散點圖
餅圖 權重圖

若要使用該控制元件,應先在工程中匯入jar包:achartengine-xxx.jar,該jar包可以在我的資源中下載。

原始碼分析:

demo的類的繼承關係圖如下所示:
類繼承關係

從類圖關係可以看出和程式碼,每個圖形的啟動需要繼承抽象類AbstractDemoChart,並重寫三個方法:getName,GetDesc,Execute。
下面以折線圖的實現類AverageTemperatureChart為例,簡單介紹實現繪圖的步驟和方法:
AverageTemperatureChart.java程式碼如下:

/**
 * Average temperature demo chart.
 */
public class AverageTemperatureChart extends AbstractDemoChart {
    /**
     * Returns the chart name.
     * 
     * @return the chart name
     */
    public String getName() {
        return "Average temperature";
    }

    /**
     * Returns the chart description.
     * 
     * @return the chart description
     */
    public String getDesc() {
        return "The average temperature in 4 Greek islands (line chart)";
    }

    /**
     * Executes the chart demo.
     * 
     * @param context
     *            the context
     * @return the built intent
     */
    public Intent execute(Context context) {
        String[] titles = new String[] { "Crete", "Corfu", "Thassos",
                "Skiathos" };
        List<double[]> x = new ArrayList<double[]>();
        for (int i = 0; i < titles.length; i++) {
            x.add(new double[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 });
        }
        List<double[]> values = new ArrayList<double[]>();
        values.add(new double[] { 12.3, 12.5, 13.8, 16.8, 20.4, 24.4, 26.4,
                26.1, 23.6, 20.3, 17.2, 13.9 });
        values.add(new double[] { 10, 10, 12, 15, 20, 24, 26, 26, 23, 18, 14,
                11 });
        values.add(new double[] { 5, 5.3, 8, 12, 17, 22, 24.2, 24, 19, 15, 9, 6 });
        values.add(new double[] { 9, 10, 11, 15, 19, 23, 26, 25, 22, 18, 13, 10 });
        int[] colors = new int[] { Color.BLUE, Color.GREEN, Color.CYAN,
                Color.YELLOW };
        PointStyle[] styles = new PointStyle[] { PointStyle.CIRCLE,
                PointStyle.DIAMOND, PointStyle.TRIANGLE, PointStyle.SQUARE };
        XYMultipleSeriesRenderer renderer = buildRenderer(colors, styles);
        int length = renderer.getSeriesRendererCount();
        for (int i = 0; i < length; i++) {
            ((XYSeriesRenderer) renderer.getSeriesRendererAt(i))
                    .setFillPoints(true);
        }
        setChartSettings(renderer, "Average temperature", "Month",
                "Temperature", 0.5, 12.5, -10, 40, Color.LTGRAY, Color.LTGRAY);
        renderer.setXLabels(12);
        renderer.setYLabels(10);
        renderer.setShowGrid(true);
        renderer.setXLabelsAlign(Align.RIGHT);
        renderer.setYLabelsAlign(Align.RIGHT);
        renderer.setZoomButtonsVisible(true);
        renderer.setPanLimits(new double[] { -10, 20, -10, 40 });
        renderer.setZoomLimits(new double[] { -10, 20, -10, 40 });

        XYMultipleSeriesDataset dataset = buildDataset(titles, x, values);
        XYSeries series = dataset.getSeriesAt(0);
        series.addAnnotation("Vacation", 6, 30);
        Intent intent = ChartFactory.getLineChartIntent(context, dataset,
                renderer, "Average temperature");
        return intent;
    }

}

程式碼的getName和getDesc方法分別返回圖形的名字和圖形的描述,用於填充主Activity的ListView中的內容;execute方法返回一個Intent物件,在execute方法中需要實現四個步驟

  1. 構建DataSet(圖表或圖形所需資料)
  2. 構建Render(該物件用於設定圖表或影象屬性)
  3. 設定Render(設定圖示屬性,如顏色,粗細,座標,長度等)
  4. 通過ChartFactory.getXxxIntent(dataset, render, …)方法,將構建的DataSet和Render物件傳入getXxxIntent方法,該方法返回的Intent用於啟動位於achartengine-1.1.0.jar包下的org.achartengine.GraphicalActivity。而該demo的啟動Activity是org.achartengine.chartdemo.demo.ChartDemo。

最後要注意的是,在AndroidManifest.xml中除了需要註冊啟動Activity——ChartDemo以及每個圖形圖表所繫結的Activity外,還需註冊GraphicalActivity

<activity android:name="org.achartengine.GraphicalActivity"/>