AChartEngine是一個開源的Android圖表庫,可以用來畫折線圖、平滑折線圖、餅圖、直方圖等等。使用簡單,功能強大。
AChartEngine官網:http://www.achartengine.org/
AChartEngine庫文件:http://repository-achartengine.forge.cloudbees.com/snapshot/org/achartengine/achartengine/1.2.0/
庫文件直接導入就可以使用了。
網上介紹AChartEngine的文章很多,不過大多數都只是貼代碼,沒有講述相關類及其原理。最新項目要畫折線圖,搜集了很多資料才弄清楚原理,在此總結整理,希望給讀者一個較清晰的理解,少走彎路。由於我的項目中只用到了折線圖,在此我只講解折線圖,其他圖標原理也是類似的。
AChartEngine官方提供的Demo中,所有的圖表都是使用Intent的方式來畫的,在實際項目中,這種方式不夠靈活,因為一個頁面不可能只顯示圖表,或者不止顯示一個圖表。
AChartEngine給我們提供了GraphicalView這個類,可以靈活的在任何位置插入圖表,非常的方便。
下面對相關類進行講解:
GraphicalView:圖表控件,是一個基本類,也是一個容器控件,所有的圖表都在此控件中呈現;
ChartFactory:工廠類,通過此類來構建不同的圖表對象,比如LineChart(折線圖)、CubeLineChart(圓滑折線圖)、PieChart(餅圖)等;
XYMultipleSeriesDataset:數據集容器,在此類中存放多條曲線的數據集合
XYMultipleSeriesRenderer:渲染器容器,此類初始化坐標系,網格,標題等,還用來存放多條曲線的渲染器
XYSeries:數據集,存放曲線的數據
XYSeriesRenderer:渲染器,存放曲線的參數,比如線條顏色,描點大小等
以下以一個簡單的動態折線圖來展現相關類的調用,其中ChartService是我自己定義的一個類,可以直接使用到實際項目中:
效果圖
MainActivity:
1 package com.example.mychartdemo; 2 3 import java.util.Timer; 4 import java.util.TimerTask; 5 6 import org.achartengine.GraphicalView; 7 8 import com.ivan.chart.ChartService; 9 10 import android.app.Activity; 11 import android.graphics.Color; 12 import android.os.Bundle; 13 import android.os.Handler; 14 import android.os.Message; 15 import android.view.Menu; 16 import android.view.ViewGroup.LayoutParams; 17 import android.widget.LinearLayout; 18 19 public class MainActivity extends Activity { 20 21 private LinearLayout mLeftCurveLayout;//存放左圖表的布局容器 22 private LinearLayout mRightCurveLayout;//存放右圖表的布局容器 23 private GraphicalView mView, mView2;//左右圖表 24 private ChartService mService, mService2; 25 private Timer timer; 26 27 @Override 28 protected void onCreate(Bundle savedInstanceState) { 29 super.onCreate(savedInstanceState); 30 setContentView(R.layout.activity_main); 31 32 mLeftCurveLayout = (LinearLayout) findViewById(R.id.left_temperature_curve); 33 mRightCurveLayout = (LinearLayout) findViewById(R.id.right_temperature_curve); 34 35 mService = new ChartService(this); 36 mService.setXYMultipleSeriesDataset("左溫度曲線"); 37 mService.setXYMultipleSeriesRenderer(100, 100, "左溫度曲線", "時間", "溫度", 38 Color.RED, Color.RED, Color.RED, Color.BLACK); 39 mView = mService.getGraphicalView(); 40 41 mService2 = new ChartService(this); 42 mService2.setXYMultipleSeriesDataset("右溫度曲線"); 43 mService2.setXYMultipleSeriesRenderer(100, 100, "右溫度曲線", "時間", "溫度", 44 Color.RED, Color.RED, Color.RED, Color.BLACK); 45 mView2 = mService2.getGraphicalView(); 46 47 //將左右圖表添加到布局容器中 48 mLeftCurveLayout.addView(mView, new LayoutParams( 49 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 50 mRightCurveLayout.addView(mView2, new LayoutParams( 51 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 52 53 timer = new Timer(); 54 timer.schedule(new TimerTask() { 55 @Override 56 public void run() { 57 handler.sendMessage(handler.obtainMessage()); 58 } 59 }, 10, 1000); 60 } 61 62 @Override 63 public boolean onCreateOptionsMenu(Menu menu) { 64 getMenuInflater().inflate(R.menu.main, menu); 65 return true; 66 } 67 68 private int t = 0; 69 private Handler handler = new Handler() { 70 @Override 71 //定時更新圖表 72 public void handleMessage(Message msg) { 73 mService.updateChart(t, Math.random() * 100); 74 mService2.updateChart(t, Math.random() * 100); 75 t+=5; 76 } 77 }; 78 79 @Override 80 protected void onDestroy() { 81 super.onDestroy(); 82 if (timer != null) { 83 timer.cancel(); 84 } 85 } 86 87 }
ChartService:
1 package com.ivan.chart; 2 3 import java.util.List; 4 5 import org.achartengine.ChartFactory; 6 import org.achartengine.GraphicalView; 7 import org.achartengine.chart.PointStyle; 8 import org.achartengine.model.XYMultipleSeriesDataset; 9 import org.achartengine.model.XYSeries; 10 import org.achartengine.renderer.XYMultipleSeriesRenderer; 11 import org.achartengine.renderer.XYSeriesRenderer; 12 import android.content.Context; 13 import android.graphics.Color; 14 import android.graphics.Paint.Align; 15 16 public class ChartService { 17 18 private GraphicalView mGraphicalView; 19 private XYMultipleSeriesDataset multipleSeriesDataset;// 數據集容器 20 private XYMultipleSeriesRenderer multipleSeriesRenderer;// 渲染器容器 21 private XYSeries mSeries;// 單條曲線數據集 22 private XYSeriesRenderer mRenderer;// 單條曲線渲染器 23 private Context context; 24 25 public ChartService(Context context) { 26 this.context = context; 27 } 28 29 /** 30 * 獲取圖表 31 * 32 * @return 33 */ 34 public GraphicalView getGraphicalView() { 35 mGraphicalView = ChartFactory.getCubeLineChartView(context, 36 multipleSeriesDataset, multipleSeriesRenderer, 0.1f); 37 return mGraphicalView; 38 } 39 40 /** 41 * 獲取數據集,及xy坐標的集合 42 * 43 * @param curveTitle 44 */ 45 public void setXYMultipleSeriesDataset(String curveTitle) { 46 multipleSeriesDataset = new XYMultipleSeriesDataset(); 47 mSeries = new XYSeries(curveTitle); 48 multipleSeriesDataset.addSeries(mSeries); 49 } 50 51 /** 52 * 獲取渲染器 53 * 54 * @param maxX 55 * x軸最大值 56 * @param maxY 57 * y軸最大值 58 * @param chartTitle 59 * 曲線的標題 60 * @param xTitle 61 * x軸標題 62 * @param yTitle 63 * y軸標題 64 * @param axeColor 65 * 坐標軸顏色 66 * @param labelColor 67 * 標題顏色 68 * @param curveColor 69 * 曲線顏色 70 * @param gridColor 71 * 網格顏色 72 */ 73 public void setXYMultipleSeriesRenderer(double maxX, double maxY, 74 String chartTitle, String xTitle, String yTitle, int axeColor, 75 int labelColor, int curveColor, int gridColor) { 76 multipleSeriesRenderer = new XYMultipleSeriesRenderer(); 77 if (chartTitle != null) { 78 multipleSeriesRenderer.setChartTitle(chartTitle); 79 } 80 multipleSeriesRenderer.setXTitle(xTitle); 81 multipleSeriesRenderer.setYTitle(yTitle); 82 multipleSeriesRenderer.setRange(new double[] { 0, maxX, 0, maxY });//xy軸的范圍 83 multipleSeriesRenderer.setLabelsColor(labelColor); 84 multipleSeriesRenderer.setXLabels(10); 85 multipleSeriesRenderer.setYLabels(10); 86 multipleSeriesRenderer.setXLabelsAlign(Align.RIGHT); 87 multipleSeriesRenderer.setYLabelsAlign(Align.RIGHT); 88 multipleSeriesRenderer.setAxisTitleTextSize(20); 89 multipleSeriesRenderer.setChartTitleTextSize(20); 90 multipleSeriesRenderer.setLabelsTextSize(20); 91 multipleSeriesRenderer.setLegendTextSize(20); 92 multipleSeriesRenderer.setPointSize(2f);//曲線描點尺寸 93 multipleSeriesRenderer.setFitLegend(true); 94 multipleSeriesRenderer.setMargins(new int[] { 20, 30, 15, 20 }); 95 multipleSeriesRenderer.setShowGrid(true); 96 multipleSeriesRenderer.setZoomEnabled(true, false); 97 multipleSeriesRenderer.setAxesColor(axeColor); 98 multipleSeriesRenderer.setGridColor(gridColor); 99 multipleSeriesRenderer.setBackgroundColor(Color.WHITE);//背景色 100 multipleSeriesRenderer.setMarginsColor(Color.WHITE);//邊距背景色,默認背景色為黑色,這里修改為白色 101 mRenderer = new XYSeriesRenderer(); 102 mRenderer.setColor(curveColor); 103 mRenderer.setPointStyle(PointStyle.CIRCLE);//描點風格,可以為圓點,方形點等等 104 multipleSeriesRenderer.addSeriesRenderer(mRenderer); 105 } 106 107 /** 108 * 根據新加的數據,更新曲線,只能運行在主線程 109 * 110 * @param x 111 * 新加點的x坐標 112 * @param y 113 * 新加點的y坐標 114 */ 115 public void updateChart(double x, double y) { 116 mSeries.add(x, y); 117 mGraphicalView.repaint();//此處也可以調用invalidate() 118 } 119 120 /** 121 * 添加新的數據,多組,更新曲線,只能運行在主線程 122 * @param xList 123 * @param yList 124 */ 125 public void updateChart(List<Double> xList, List<Double> yList) { 126 for (int i = 0; i < xList.size(); i++) { 127 mSeries.add(xList.get(i), yList.get(i)); 128 } 129 mGraphicalView.repaint();//此處也可以調用invalidate() 130 } 131 }
布局文件:activity_main:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 android:paddingBottom="@dimen/activity_vertical_margin" 7 android:paddingLeft="@dimen/activity_horizontal_margin" 8 android:paddingRight="@dimen/activity_horizontal_margin" 9 android:paddingTop="@dimen/activity_vertical_margin" 10 tools:context=".MainActivity" > 11 12 <LinearLayout 13 android:layout_width="match_parent" 14 android:layout_height="0dp" 15 android:layout_marginBottom="20dp" 16 android:layout_weight="1" 17 android:orientation="vertical" > 18 19 <TextView 20 android:layout_width="wrap_content" 21 android:layout_height="wrap_content" 22 android:layout_marginBottom="10dp" 23 android:text="左溫度曲線" /> 24 25 <LinearLayout 26 android:id="@+id/left_temperature_curve" 27 android:layout_width="match_parent" 28 android:layout_height="match_parent" 29 android:orientation="horizontal" > 30 </LinearLayout> 31 </LinearLayout> 32 33 <LinearLayout 34 android:layout_width="match_parent" 35 android:layout_height="0dp" 36 android:layout_weight="1" 37 android:orientation="vertical" > 38 39 <TextView 40 android:layout_width="wrap_content" 41 android:layout_height="wrap_content" 42 android:layout_marginBottom="10dp" 43 android:text="右溫度曲線" /> 44 45 <LinearLayout 46 android:id="@+id/right_temperature_curve" 47 android:layout_width="match_parent" 48 android:layout_height="match_parent" 49 android:orientation="horizontal" > 50 </LinearLayout> 51 </LinearLayout> 52 53 </LinearLayout>
詳細說明見注釋。
AChartEngine功能真的很強大,之前一直想要自己來畫曲線圖,浪費了幾天功夫。所以說,站在巨人的肩膀上是很重要的。對於程序員,有一句很重要的話,叫做不要重復造輪子。但是,要使用別人的輪子,必須先要理解透徹,否則很難實現漂亮的效果。
由於筆者水平有限,如有錯漏之處在所難免,歡迎讀者批評指正,感激不盡!
原創文章,轉載請注明出處。
全文完