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: package com.example.mychartdemo; import java.util.Timer; import java.util.TimerTask; import org.achartengine.GraphicalView; import com.ivan.chart.ChartService; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Menu; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; public class MainActivity extends Activity { private LinearLayout mLeftCurveLayout;//存放左图表的布局容器 private LinearLayout mRightCurveLayout;//存放右图表的布局容器 private GraphicalView mView, mView2;//左右图表 private ChartService mService, mService2; private Timer timer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLeftCurveLayout = (LinearLayout) findViewById(R.id.left_temperature_curve); mRightCurveLayout = (LinearLayout) findViewById(R.id.right_temperature_curve); mService = new ChartService(this); mService.setXYMultipleSeriesDataset("左温度曲线"); mService.setXYMultipleSeriesRenderer(100, 100, "左温度曲线", "时间", "温度", Color.RED, Color.RED, Color.RED, Color.BLACK); mView = mService.getGraphicalView(); mService2 = new ChartService(this); mService2.setXYMultipleSeriesDataset("右温度曲线"); mService2.setXYMultipleSeriesRenderer(100, 100, "右温度曲线", "时间", "温度", Color.RED, Color.RED, Color.RED, Color.BLACK); mView2 = mService2.getGraphicalView(); //将左右图表添加到布局容器中 mLeftCurveLayout.addView(mView, new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mRightCurveLayout.addView(mView2, new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { handler.sendMessage(handler.obtainMessage()); } }, 10, 1000); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } private int t = 0; private Handler handler = new Handler() { @Override //定时更新图表 public void handleMessage(Message msg) { mService.updateChart(t, Math.random() * 100); mService2.updateChart(t, Math.random() * 100); t+=5; } }; @Override protected void onDestroy() { super.onDestroy(); if (timer != null) { timer.cancel(); } } } ChartService: package com.ivan.chart; import java.util.List; import org.achartengine.ChartFactory; import org.achartengine.GraphicalView; import org.achartengine.chart.PointStyle; import org.achartengine.model.XYMultipleSeriesDataset; import org.achartengine.model.XYSeries; import org.achartengine.renderer.XYMultipleSeriesRenderer; import org.achartengine.renderer.XYSeriesRenderer; import android.content.Context; import android.graphics.Color; import android.graphics.Paint.Align; public class ChartService { private GraphicalView mGraphicalView; private XYMultipleSeriesDataset multipleSeriesDataset;// 数据集容器 private XYMultipleSeriesRenderer multipleSeriesRenderer;// 渲染器容器 private XYSeries mSeries;// 单条曲线数据集 private XYSeriesRenderer mRenderer;// 单条曲线渲染器 private Context context; public ChartService(Context context) { this.context = context; } /** * 获取图表 * * @return */ public GraphicalView getGraphicalView() { mGraphicalView = ChartFactory.getCubeLineChartView(context, multipleSeriesDataset, multipleSeriesRenderer, 0.1f); return mGraphicalView; } /** * 获取数据集,及xy坐标的集合 * * @param curveTitle */ public void setXYMultipleSeriesDataset(String curveTitle) { multipleSeriesDataset = new XYMultipleSeriesDataset(); mSeries = new XYSeries(curveTitle); multipleSeriesDataset.addSeries(mSeries); } /** * 获取渲染器 * * @param maxX * x轴最大值 * @param maxY * y轴最大值 * @param chartTitle * 曲线的标题 * @param xTitle * x轴标题 * @param yTitle * y轴标题 * @param axeColor * 坐标轴颜色 * @param labelColor * 标题颜色 * @param curveColor * 曲线颜色 * @param gridColor * 网格颜色 */ public void setXYMultipleSeriesRenderer(double maxX, double maxY, String chartTitle, String xTitle, String yTitle, int axeColor, int labelColor, int curveColor, int gridColor) { multipleSeriesRenderer = new XYMultipleSeriesRenderer(); if (chartTitle != null) { multipleSeriesRenderer.setChartTitle(chartTitle); } multipleSeriesRenderer.setXTitle(xTitle); multipleSeriesRenderer.setYTitle(yTitle); multipleSeriesRenderer.setRange(new double[] { 0, maxX, 0, maxY });//xy轴的范围 multipleSeriesRenderer.setLabelsColor(labelColor); multipleSeriesRenderer.setXLabels(10); multipleSeriesRenderer.setYLabels(10); multipleSeriesRenderer.setXLabelsAlign(Align.RIGHT); multipleSeriesRenderer.setYLabelsAlign(Align.RIGHT); multipleSeriesRenderer.setAxisTitleTextSize(20); multipleSeriesRenderer.setChartTitleTextSize(20); multipleSeriesRenderer.setLabelsTextSize(20); multipleSeriesRenderer.setLegendTextSize(20); multipleSeriesRenderer.setPointSize(2f);//曲线描点尺寸 multipleSeriesRenderer.setFitLegend(true); multipleSeriesRenderer.setMargins(new int[] { 20, 30, 15, 20 }); multipleSeriesRenderer.setShowGrid(true); multipleSeriesRenderer.setZoomEnabled(true, false); multipleSeriesRenderer.setAxesColor(axeColor); multipleSeriesRenderer.setGridColor(gridColor); multipleSeriesRenderer.setBackgroundColor(Color.WHITE);//背景色 multipleSeriesRenderer.setMarginsColor(Color.WHITE);//边距背景色,默认背景色为黑色,这里修改为白色 mRenderer = new XYSeriesRenderer(); mRenderer.setColor(curveColor); mRenderer.setPointStyle(PointStyle.CIRCLE);//描点风格,可以为圆点,方形点等等 multipleSeriesRenderer.addSeriesRenderer(mRenderer); } /** * 根据新加的数据,更新曲线,只能运行在主线程 * * @param x * 新加点的x坐标 * @param y * 新加点的y坐标 */ public void updateChart(double x, double y) { mSeries.add(x, y); mGraphicalView.repaint();//此处也可以调用invalidate() } /** * 添加新的数据,多组,更新曲线,只能运行在主线程 * @param xList * @param yList */ public void updateChart(List<Double> xList, List<Double> yList) { for (int i = 0; i < xList.size(); i++) { mSeries.add(xList.get(i), yList.get(i)); } mGraphicalView.repaint();//此处也可以调用invalidate() } }
布局文件:activity_main:
<LinearLayout xmlns:android=" http://schemas.android.com/apk/res/android " xmlns:tools=" http://schemas.android.com/tools " android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginBottom="20dp" android:layout_weight="1" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:text="左温度曲线" /> <LinearLayout android:id="@+id/left_temperature_curve" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > </LinearLayout> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:text="右温度曲线" /> <LinearLayout android:id="@+id/right_temperature_curve" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > </LinearLayout> </LinearLayout> </LinearLayout>
详细说明见注释。
AChartEngine功能真的很强大,之前一直想要自己来画曲线图,浪费了几天功夫。所以说,站在巨人的肩膀上是很重要的。对于程序员,有一句很重要的话,叫做不要重复造轮子。但是,要使用别人的轮子,必须先要理解透彻,否则很难实现漂亮的效果。