使用AChartEngine画动态曲线图

版权所有,禁止匿名转载;禁止商业使用。

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是我自己定义的一个类,可以直接使用到实际项目中:

效果图

202128248909559.png

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功能真的很强大,之前一直想要自己来画曲线图,浪费了几天功夫。所以说,站在巨人的肩膀上是很重要的。对于程序员,有一句很重要的话,叫做不要重复造轮子。但是,要使用别人的轮子,必须先要理解透彻,否则很难实现漂亮的效果。

 

0 0