1. 程式人生 > >安卓 動態折線圖

安卓 動態折線圖

安卓 動態折線圖

一、簡述

      記--一個簡單的動態折線圖。資料為隨機數。

      例子打包:連結: https://pan.baidu.com/s/12IdD6eayEvRPeFvoymuCcg 提取碼: 9vu7 

二、效果

                                         

三、工程結構

四、原始檔

MainActivity.java檔案

package com.liang.chart;

import java.util.Random;

import org.achartengine.chart.PointStyle;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.app.Activity;
import android.graphics.Color;

public class MainActivity extends Activity {

	private LineChart mLineChart;//直線圖類
	private boolean addData_thread_run; // 控制新增折線圖資料執行緒的退出
	private int x_index;// X軸的刻度值
	private Random random;// 用來獲取隨機數
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);//設定主介面
		
		//建立折線圖例項 (X軸標題,Y軸標題,X軸的最小值,X軸的最大值,Y軸的最小值,Y軸的最大值,座標軸的顏色,刻度值的顏色)
		mLineChart = new LineChart("時間(min)", "", 0, 100, 0, 9500, Color.WHITE, Color.WHITE);
		
		x_index = 50;//初始化X軸的刻度值
		random = new Random();
	};
	
	@Override
	protected void onResume() //在本頁面onStart()之後設定為繪圖所在的頁面
	{
		super.onResume();
		
		//設定圖表顯示頁面為本頁面
		mLineChart.setChartViewActivity(this);
		
		//新增4條折線
		mLineChart.addLineToChart("折線A", PointStyle.CIRCLE, Color.BLUE);//新增折線A
		mLineChart.addLineToChart("折線B", PointStyle.DIAMOND, Color.GREEN);//新增折線B
		mLineChart.addLineToChart("折線C", PointStyle.TRIANGLE, Color.CYAN);//新增折線C
		mLineChart.addLineToChart("折線D", PointStyle.SQUARE, Color.YELLOW);//新增折線D
		
	}
	
	// 訊息控制代碼(執行緒裡無法進行介面更新,所以要把訊息從執行緒裡傳送出來在訊息控制代碼裡進行處理)
		public Handler mHandler = new Handler() 
		{
			@Override
			public void handleMessage(Message msg) 
			{
				switch (msg.what) 
				{
				case 0:
					//新增資料 (新增折點)
					mLineChart.addData("折線A", x_index, random.nextInt(9000) );
					mLineChart.addData("折線B", x_index, random.nextInt(9000) );
					mLineChart.addData("折線C", x_index, random.nextInt(9000) );
					mLineChart.addData("折線D", x_index, random.nextInt(9000) );
					
					
					x_index += 10; // X軸每次右移10個刻度
					mLineChart.moveChart(10);// 圖示右移10刻度值
					
					//繪製折線圖(更新UI)
					mLineChart.mChartView.repaint();
					break;
				}
			}
		};
	
	// "開始"按鈕的點選響應動作
	public void onButtonStartClicked(View v)
	{
		Button btn_start = (Button)v;// 拿到按鈕控制代碼
		if( btn_start.getText().toString().equals("開始") )
		{// 點選的是"開始"
			new Thread(addData_thread).start() ;// 開啟子執行緒,開始動態的新增資料
			btn_start.setText("停止");// 設定按鈕文字為 "停止"
		}
		else // 點選的是"停止"
		{
			addData_thread_run = false;// 結束子執行緒,停止新增資料
			btn_start.setText("開始");// 設定按鈕文字為 "開始"
		}
		
	}
	
	//新增折線圖資料的執行緒
	private Runnable addData_thread = new Runnable()
	{
		@Override
		public void run()
		{
			
			addData_thread_run = true;
			while(addData_thread_run)
			{
				try {
					Thread.sleep(1000);// 延時1秒
					mHandler.sendEmptyMessage(0);// 傳送0型別資訊,通知主執行緒更新圖表
					
				} catch (InterruptedException e) 
				{
					break;
				}
			}
		}
	};

}//end with MainActivity

LineChart.java檔案

package com.liang.chart;

import java.util.ArrayList;
import java.util.List;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.PointStyle;
import org.achartengine.model.SeriesSelection;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;

import com.liang.chart.R;

import android.app.Activity;
import android.graphics.Color;
import android.graphics.Paint.Align;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.Toast;

//折線圖 類
public class LineChart 
{
	// 渲染資料集 (圖表的資料,折線的折點座標資訊等)
	private XYMultipleSeriesDataset mDataset;
	
	// 多重圖層渲染器 (可以看做是總渲染器(含多個子渲染器),繪製背景網格,折線圖等)
	private XYMultipleSeriesRenderer mMltRenderer;
	
	// 折線集合
	private List<XYSeries> mSeriesList;
		
	
	// 標記折線圖是否可以拖動
	public boolean mIsCanMove = true;

	// 圖表檢視(就是最後繪製出來的整個折線圖)
	public GraphicalView mChartView;

	//無參建構函式 (如果有 有引數的建構函式,就不會自動新增無參建構函式,最好自己加上無參建構函式,)
	public LineChart(){}
	

	/* 有參建構函式
	 *   設定圖表屬性
	 *   xTitle:X軸標題
	 *   yTitle:Y軸標題
	 *   xMin:X軸的最小值
	 *   xMax:X軸的最大值
	 *   yMin:Y軸的最小值
	 *   yMax:Y軸的最大值
	 *   axisColor:座標軸的顏色 
	 *   labelsColor:標籤的顏色(標籤:也就是座標軸上的刻度值10,20...80)
	 */
	public LineChart(String xTitle, String yTitle, double xMin,
			double xMax, double yMin, double yMax, int axisColor, int labelsColor) 
	{
		mDataset = new XYMultipleSeriesDataset();// 例項化資料集物件
		mMltRenderer = new XYMultipleSeriesRenderer();// 例項化多層渲染器物件
		mSeriesList = new ArrayList<XYSeries>(); // 初始化折線集合
		
		mMltRenderer.setXTitle(xTitle);// 設定X軸標題
		mMltRenderer.setYTitle(yTitle);// 設定Y軸標題
		mMltRenderer.setXAxisMin(xMin);// 設定X軸的最小值
		mMltRenderer.setXAxisMax(xMax);// 設定X軸的最大值
		mMltRenderer.setYAxisMin(yMin);// 設定Y軸的最小值
		mMltRenderer.setYAxisMax(yMax);// 設定Y軸的最大值
		mMltRenderer.setAxesColor(axisColor);// 設定座標軸顏色
		mMltRenderer.setLabelsColor(labelsColor);// 設定標籤(刻度值)顏色
		mMltRenderer.setShowGrid(true);// 顯示網格
		mMltRenderer.setGridColor(Color.GRAY);// 設定網格顏色
		mMltRenderer.setXLabels(10);// 設定X軸的標籤數(有幾個刻度)
		mMltRenderer.setXLabelsPadding(10);//設定X軸標籤的間距
		mMltRenderer.setYLabels(16);// 設定Y軸的標籤數
		mMltRenderer.setYLabelsAlign(Align.RIGHT);// 設定Y軸標籤的方向
		mMltRenderer.setPointSize((float) 2);//設定折線點的大小
		mMltRenderer.setShowLegend(true);// 下面的 圖例標註,如圓點的藍色的折線是X軸...
		mMltRenderer.setZoomButtonsVisible(false);// 隱藏放大縮小按鈕
		mMltRenderer.setZoomEnabled(true, false);// 設定縮放,這邊是橫向可以縮放,豎向不能縮放
		mMltRenderer.setPanEnabled(true, false);// 設定滑動,這邊是橫向可以滑動,豎向不可滑動
		
	}

	//新增一條折線到圖表
	public void addLineToChart(String lineTitle, PointStyle pointStyle, int lineColor)
	{
		XYSeriesRenderer serRender = new XYSeriesRenderer();//建立1個子渲染器
		XYSeries series = new XYSeries(lineTitle);//建立1條折線
		
		mMltRenderer.addSeriesRenderer(serRender);// 將子渲染器新增到總渲染器
		mDataset.addSeries(series);// 將折線新增到資料集
		mSeriesList.add(series);// 將折線新增到折線集合
		
		// 設定折線渲染屬性
		serRender.setPointStyle(pointStyle);// 設定折點的樣式
		serRender.setColor(lineColor);// 設定折線的顏色
		serRender.setFillPoints(true);// 設定折點是實心還是空心
		serRender.setDisplayChartValues(false);// 不顯示折點的Y值
		serRender.setDisplayChartValuesDistance(10);// 設定數值與折點的距離
		
	}

	//設定圖表的顯示頁面 (activity:圖表顯示所在的頁面)
	public void setChartViewActivity(final Activity activity) 
	{
		if (mChartView == null) 
		{
			//獲取一個layout,用來顯示圖表
			LinearLayout layout = (LinearLayout) activity.findViewById(R.id.chart);
			//生成圖表
			mChartView = ChartFactory.getLineChartView(activity, mDataset,mMltRenderer);
			
			mMltRenderer.setClickEnabled(true);// 可以響應點選
			mMltRenderer.setSelectableBuffer(10);// 設定點的緩衝半徑值(在某點附近點選時,在點的半徑範圍內都算點選這個點)
			
			//折線的點選響應
			mChartView.setOnClickListener(new View.OnClickListener() {
				public void onClick(View v) {
					// 拿到點選的折線物件、折點
					SeriesSelection seriesSelection = mChartView.getCurrentSeriesAndPoint();
					if (seriesSelection != null) 
					{
						// 將所點選的點的資訊通過Toast展示(點選的是那一條折線,第幾個折點,座標值)
						Toast.makeText(activity,
								  "折線:"+ seriesSelection.getSeriesIndex()
								+ "\n點: "+ seriesSelection.getPointIndex()
								+ "\nX="+ seriesSelection.getXValue() + ", Y="+ seriesSelection.getValue(),
								Toast.LENGTH_SHORT).show();
					}
				}
			});
			
			// 將圖表新增到layout中
			layout.addView(mChartView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		} 
		else 
		{
			mChartView.repaint();//繪製折線圖(重繪,更新)
		}
	}

	// 向某條折線新增折點(x,y) (新增資料)lineTitle:折線的標題
	public void addData(String lineTitle, double x, double y) 
	{
		if(mSeriesList.size() > 0 )//有折線
		{
			for(XYSeries ser : mSeriesList)//遍歷折線集合
			{
				if(ser.getTitle().equals(lineTitle))// 找到指定的折線
				{
					ser.add(x, y);
					break;
				}
			}
		}
	}
	
	// 拖動圖表  設定X軸的當前顯示向右移val
	public void moveChart(int val) 
	{
		// 計算當前X軸可視長度,也就是當前看到的X軸上的右刻度與左刻度之差(縮放按鈕能夠影響看到的刻度值範圍)
		double dis = mMltRenderer.getXAxisMax() - mMltRenderer.getXAxisMin();
		
		double max = val + mMltRenderer.getXAxisMax();
		double min = max - dis;
		mMltRenderer.setXAxisMin(min);// 設定X軸顯示的左刻度值
		mMltRenderer.setXAxisMax(max);// 設定X軸顯示的右刻度值
		
	}
}

佈局檔案

activity_main.xml檔案

<RelativeLayout 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"
    tools:context=".MainActivity" >

     <LinearLayout
         android:id="@+id/linear_layout"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="horizontal" >

		<Button
		    android:id="@+id/btn_start"
		    android:layout_width="wrap_content"
		    android:layout_height="wrap_content"
		    android:onClick="onButtonStartClicked"
		    android:text="開始" />

    </LinearLayout>

     <LinearLayout
         android:id="@+id/chart"
         android:layout_width="fill_parent"
         android:layout_height="300dp"
         android:layout_alignParentBottom="true"
         android:layout_alignParentLeft="true"
         android:layout_below="@+id/linear_layout"
         android:orientation="horizontal" >

     </LinearLayout>
	 
</RelativeLayout>

 

五、總結

     1、產生指定範圍的隨機數

Random random = new Random();
int num = random.nextInt(n);// 作用是生成一個隨機的int值,該值介於[0,n)的區間,也就是0到n之間的隨機int值,包含0而不包含n。

// 生成指定範圍的隨機數
int num = random.nextInt(b)%(b-a+1) + a;//生成[a,b],包含a,b

// 如生成[1,100],即1到100,包括1和100
int a = 1;
int b = 100; 
int num = random.nextInt(b)%(b-a+1) + a;

   2、結束執行緒:使用控制變數來結束執行緒迴圈 或者用stop()方法(好像說不安全)

   3、執行緒一般不能二次start(),所以例子中每次開始新建子執行緒。