安卓 动态折线图

安卓 动态折线图

一、简述

      记--一个简单的动态折线图。数据为随机数。

      例子打包:链接: 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(),所以例子中每次开始新建子线程。

猜你喜欢

转载自blog.csdn.net/nanfeibuyi/article/details/83997139
今日推荐