在ACE 中,Embedded Chart实际上是一个 GraphicalView对象。与一般的Chart不同,它可以嵌入到另一个Activity中(其实就是一个普通的 view),而不必通过Intent来调用。这样做的好处在于,我们可以更灵活地定制这个GraphicalView ,比如在图表中放置一些其他的view,比如按钮、图片等。
下面我们演示如何使用 Embedded Chart。 可以看到,在这个自定义的折线图中,我们不但在GraphicalView上加入了一个Label控件和一个按钮,甚至还显示了自己的背景图。
AndroidMainifest.xml
在其中加入一个新的Activity,比如就叫做test.ace.EmbeddedChart:
<activity android:name="test.ace.EmbeddedChart"/>
这是一个普通的Activity类,我们在其中嵌入一个GraphicalView,以演示EmbeddedChart 的例子。下面我们来实现这个Activity。
Layout 文件
一个Activity一个xml布局文件,这里也不例外,我们把它命名为embeddedchart.xml,放在res/layout 目录下:
<?xml version="1.0" encoding="utf-8"?>
<!-- 注意 android:background 属性的使用,为 Activity 加了一个背景图 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent" android:background="@drawable/icon"
android:layout_height="fill_parent">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Embedded Chart 演示" />
<Button android:id="@+id/button1" android:text="button1"
android:layout_width="wrap_content" android:layout_height="wrap_content" />
<!-- 这个 LinearLayout 用于放置 GraphicalView -->
<LinearLayout android:id="@+id/chart" android:orientation="horizontal"
android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" />
</LinearLayout>
EmbeddedChart.java
这个就是Activity 类的实现,在其中我们用GraphicalView 生成了一个折线图并嵌入其中:
首先我们声明几个成员变量:
privateXYMultipleSeriesDataset ds;
privateXYMultipleSeriesRenderer render;
private XYSeries series;
private GraphicalView gv;
private XYSeriesRenderer xyRender;
除了private GraphicalView gv 是Embedded Chart 特别要用到的之外,所有变量都是我们前面画柱状图和折线图中已经用到过的。
接下来是两个特殊方法:
protected voidonSaveInstanceState(Bundle outState) {
Log.i("onSaveInstanceState","onSaveInstanceState");
super.onSaveInstanceState(outState);
outState.putSerializable("dataset", ds);
outState.putSerializable("renderer", render);
outState.putSerializable("current_series", series);
outState.putSerializable("current_renderer", xyRender);
}
// 恢复 Activity 时,反序列化已保存的数据。
protected voidonRestoreInstanceState(Bundle savedState) {
Log.i("onRestoreInstanceState","onRestoreInstanceState");
super.onRestoreInstanceState(savedState);
ds = (XYMultipleSeriesDataset) savedState.getSerializable("dataset");
render = (XYMultipleSeriesRenderer) savedState.getSerializable("renderer");
series = (XYSeries) savedState.getSerializable("current_series");
xyRender = (XYSeriesRenderer) savedState.getSerializable("current_renderer");
}
这两个方法是专门用于在Activity挂起操作、唤醒操作时使用的。比如程序运行过程中用户按下了Home键或接听键(挂起),以及Activity被挂起后又再次被启动(唤醒)。
onSaveInstanceState 方法在挂起时被调用,我们在这里使用序列化方法(putSerializable方法)把Activity的成员变量储存到Bundle。
onRestoreInstanceState 方法在 Activity 唤醒时调用,在此我们使用反序列化方法(getSerializable方法)从Bundle中恢复成员变量的值。
此外,还有两个方法也是成对使用的。
// 注意,在调用 onCreate 之后会调用 onResume
protected void onResume() {
Log.i("onResume","onResume");
super.onResume();
if(ds==null)getDataset();
if(render==null)getRenderer();
if (gv == null) {
LinearLayout layout =(LinearLayout) findViewById(R.id.chart);
gv = ChartFactory.getLineChartView(this, ds, render);
layout.addView(gv, newLayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
} else {
// 绘制图形
gv.repaint();
}
}
// 注意每次startActivity(this,EmbeddedChart.class) 之后会调用 onCreate
protected void onCreate(BundlesavedInstanceState) {
Log.i("onCreate","onCreate");
// 初始化 Activity 视图
super.onCreate(savedInstanceState);
setContentView(R.layout.embeddedchart);
}
一般来说,只要用startActivity方法启动的Activity,都会依次调用该Activity的onCreate方法和onResume方法。
onCreate方法很简单就不说了。在onResume方法中,我们调用getDataset方法构造了折线图的点数据,用getRenderer方法构造了折线图的Renderer,然后用ChartFactory.getLineChartView构造了一个GraphicalView,最后把这个GraphicalView 加到id为chart的LinearLayout中。于是在 Activity 上显示了折线图。
最后是getDataset和getRenderer 方法的实现:
privateXYMultipleSeriesDataset getDataset() {
ds = newXYMultipleSeriesDataset();
final int nr = 10;// 每个系列种包含10个随机数
Random r = new Random();
for (int i = 0; i < 1;i++) {
// 新建一个系列(线条)
series = new XYSeries("Series" + (i + 1));
for (int k = 0; k < nr;k++) {
int x=r.nextInt()%10;// x:0-10之间的随机整数
inty=50+r.nextInt()%50;// y:50-100之间的随机整数
series.add(x,y);// 往系列中加入一个随机分布的点
}
// 把添加了点的折线放入dataset
ds.addSeries(series);
}
return ds;
}
publicXYMultipleSeriesRenderer getRenderer() {
// 新建一个xymultipleseries
render = newXYMultipleSeriesRenderer();
render.setAxisTitleTextSize(16); // 设置坐标轴标题文本大小
render.setChartTitleTextSize(20); // 设置图表标题文本大小
render.setLabelsTextSize(15); // 设置轴标签文本大小
render.setLegendTextSize(15); // 设置图例文本大小
render.setMargins(new int[] {20, 30, 15,0}); // 设置4边留白
render.setPanEnabled(false, false); // 设置x,y坐标轴不会因用户划动屏幕而移动
// 设置4边留白透明
//
render.setMarginsColor(Color.argb(0,0xff, 0, 0));
render.setBackgroundColor(Color.TRANSPARENT); // 设置背景色透明
render.setApplyBackgroundColor(true); // 使背景色生效
// 设置一个系列的颜色为蓝色
xyRender = newXYSeriesRenderer();
xyRender.setColor(Color.BLUE);
// 往xymultiplerender中增加一个系列
render.addSeriesRenderer(xyRender);
return render;
}
这两个方法在前面《使用 AChartEngine 画折线图》已有介绍,就不多说了。唯一值得注意的是,在使用setMarginsColor 方法设置4边背景色透明时,不能使用 Color.TRANSPARENT 或者 DefaultRenderer.NO_COLOR,这两个透明色在setMarginsColor 方法中是无效的,要用该方法设置4边透明只能用 Color.argb 方法。 argb (int alpha, int red, int green, int blue) 方法的第1个参数alpha值为00时可以获得透明色,其他颜色值任意,例如:0x00ff0000。而setBackgroundColor 方法中 Color.TRANSPARENT 是有效的——它可以把 chart 的中心区域的背景设置为透明色。不知是否是 bug。
EmbeddedChart的调用
要使用这个EmbeddedChart类跟一般的Activity没有任何区别,直接在另一个Activity中使用下面的语句:
intent=new Intent(this,EmbeddedChart.class);
startActivity(intent);
程序运行后如下图所示: