在android中实现动态跑动的图表实现方法
仿ES界面写的文件浏览器
http://www.eoeandroid.com/thread-226511-1-1.html
Android 新版捕鱼达人源码
http://www.eoeandroid.com/thread-197437-1-1.html
Android的学习初体验猜牌游戏源码
http://www.eoeandroid.com/thread-163542-1-1.html
实现这个的目的是为了在手机屏幕上能够动态显示接收的数据,适合哪种不断有新数据接收时需要时时展现的程序。
首先我们采用的实现方式是:SurfaceView的onDraw实现,初始化一个view,画已有的点,提供添加点的接口给它的Activity调用,onDraw方法要实现根据点的数组画点。
首先我利用了以前写的一个游戏的VIew它实现了不间断的调用onDraw,这样才能保证点是一直跑动的,代码:
import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * * Copyright (c) 2012 All rights reserved * 名称:GameView.java * 描述:继承自该类的view只需要考虑怎么绘制画面 * 需要实现draw(Canvas canvas)方法 * 注意:实现的draw方法中不要锁定、解锁画布 * 不要进行异常处理 * @author zhaoqp * @date:2012-10-30 下午4:42:32 * @version v1.0 */ public abstract class GameView extends SurfaceView implements SurfaceHolder.Callback{ private static final String TAG = "GameView"; public ViewThread thread; //刷帧的线程 //定义SurfaceHolder对象 private SurfaceHolder mSurfaceHolder = null; public String fps="FPS:N/A"; //用于显示帧速率的字符串,调试使用 private boolean loop = true; private boolean pause = true; //睡眠的毫秒数 private int sleepSpan = 100; public GameView(Context context){ super(context); init(); } public GameView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public GameView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public void init(){ //Log.d(TAG, "--GameView Created--"); // 实例化SurfaceHolder mSurfaceHolder = this.getHolder(); // 添加回调 mSurfaceHolder.addCallback(this); this.setFocusable(true); thread = new ViewThread(mSurfaceHolder,this); thread.start(); } /** * 设置刷新的sleep间隔时间 */ public void setSleep(int time){ this.sleepSpan = time; } /** * 设置循环标记位 * @param loop */ public void setLoop(boolean loop) { this.loop = loop; } /** * 设置循环暂停标记位 * @param pause */ public void setPause(boolean pause) { this.pause = pause; } /** * 绘图 */ public abstract void onDraw(Canvas canvas); /** * 在surface创建时激发的扩展方法 */ public void expandSurfaceCreated(){ } /** * 在surface创建时激发的扩展方法 */ public void expandSurfaceDestroyed(){ } /** * 在surface的大小发生改变时激发 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){ } /** * 在surface销毁时激发 */ @Override public void surfaceCreated(SurfaceHolder holder){ //如果后台重绘线程没起来,就启动它 if(! this.thread.isAlive()){ try{ //启动刷帧线程 this.setLoop(true); this.setPause(true); this.thread.start(); expandSurfaceCreated(); }catch(Exception e){ e.printStackTrace(); this.setLoop(false); this.setPause(false); } } Log.d(TAG, "--surfaceCreated--"); } /** * 在surface销毁时激发 */ @Override public void surfaceDestroyed(SurfaceHolder holder){ releaseViewThread(); Log.d(TAG, "--surfaceDestroyed--"); } /** * 释放view类线程 */ public void releaseViewThread(){ if(thread != null && thread.isAlive()){ this.setPause(false); this.setLoop(false); try { thread.interrupt(); }catch (Exception e) { e.printStackTrace(); } } thread = null; } /** * 触摸屏事件 * @param event */ public void onMyTouchEvent(MotionEvent event){ } /** * 按键事件按下 * @param keyCode * @param event */ public void onMyKeyDown(int keyCode, KeyEvent event) { } /** * 按键事件抬起 * @param keyCode * @param event */ public void onMyKeyUp(int keyCode, KeyEvent event) { } /** * 滚动事件 * @param event */ public void onMyTrackballEvent(MotionEvent event) { } /** * 刷帧线程 */ class ViewThread extends Thread{ private SurfaceHolder surfaceHolder; private GameView gameView; private int count = 0; //记录帧数,该变量用于计算帧速率 private long start = System.nanoTime(); //记录起始时间,该变量用于计算帧速率 /** * 构造方法 * @param surfaceHolder * @param gameView */ public ViewThread(SurfaceHolder surfaceHolder, GameView gameView) { this.surfaceHolder = surfaceHolder; this.gameView = gameView; } @Override public void run() { Canvas canvas; while (loop) { while (pause) { canvas = null; try { if(!Thread.currentThread().isInterrupted()){ //锁定整个画布,在内存要求比较高的情况下,建议参数不要为null canvas = this.surfaceHolder.lockCanvas(); synchronized (this.surfaceHolder) { gameView.onDraw(canvas);//绘制 } } }catch (Exception e){ e.printStackTrace(); Thread.currentThread().interrupt(); loop = false; }finally { if (canvas != null) { //更新屏幕显示内容 this.surfaceHolder.unlockCanvasAndPost(canvas); } } this.count++; if(count == 20){ //如果计满20帧 count = 0; //清空计数器 long tempStamp = System.nanoTime(); //获取当前时间 long span = tempStamp - start; //获取时间间隔 start = tempStamp; //为start重新赋值 double fps = Math.round(100000000000.0/span*20)/100.0;//计算帧速率 gameView.fps = "FPS:"+fps;//将计算出的帧速率设置到gameView的相应字符串对象中 } try{ Thread.sleep(sleepSpan); //睡眠指定毫秒数 }catch(Exception e){ e.printStackTrace(); //打印堆栈信息 } } } } } }
接下来实现这个View
这个View要实现能够根据数组中的点时时绘制,其中x轴每个单位的间距我设置为50,通过offect实现点的慢移动,代码:
public class VisualizerView extends GameView { private float[] mPoints; private float[] mPointsDraw; // 画笔 private Paint mPaint = new Paint(); private int offect = 0; // 初始化画笔 private void init1() { mPaint.setAntiAlias(true); mPaint.setFakeBoldText(true); mPaint.setTextSize(13); } public VisualizerView(Context context) { super(context); init1(); } public VisualizerView(Context context, AttributeSet attr) { super(context, attr); init1(); } public void updateVisualizer(float[] points) { if(points != null){ this.mPoints = points; mPointsDraw = new float[points.length-1]; System.out.println("新点旧加入"); offect = 0; } //一个点进来 要执行多次onDraw,将点缓缓移动 //移动50次 //invalidate(); } @Override public void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); mPaint.setStrokeWidth(0.2f); //底线 mPaint.setColor(Color.RED); //canvas.drawLine(0, getHeight(), getWidth(), getHeight(), mPaint); //顶线 mPaint.setColor(Color.RED); //canvas.drawLine(0, 0, getWidth(), 0, mPaint); //中线 mPaint.setColor(Color.GRAY); canvas.drawLine(0, getHeight()/2, getWidth(),getHeight()/2, mPaint); //每个单位20大小 //99 mPaint.setColor(Color.RED); canvas.drawLine(0, getHeight()/2+40,getWidth(),getHeight()/2+40, mPaint); //95 canvas.drawLine(0, getHeight()/2-40,getWidth(),getHeight()/2-40, mPaint); mPaint.setColor(Color.GRAY); canvas.drawText("99", 0, getHeight()/2-42, mPaint); canvas.drawText("95", 0, getHeight()/2+40, mPaint); if (mPoints != null && mPoints.length>1) { mPointsDraw = new float[99]; //把中线认为是97,计算点的偏移 for (int i = 1; i < mPoints.length; i++) { if(mPoints[i]!=0){ float offect = mPoints[i]-97; offect = offect*20; mPointsDraw[i-1] = getHeight()/2-offect; }else{ mPointsDraw[i-1] = 97; } } mPaint.setStrokeWidth(1f); //最后结果 for (int i = 0; i < mPointsDraw.length; i++) { mPaint.setColor(Color.GRAY); canvas.drawCircle(50*i-offect,mPointsDraw[i], 2, mPaint); canvas.drawText(String.valueOf((int)mPoints[i+1]), (float)50*i-offect-10, mPointsDraw[i]-3, mPaint); mPaint.setColor(Color.BLUE); canvas.drawLine(50*i-offect, mPointsDraw[i], 50*(i+1)-offect,mPointsDraw[i], mPaint); } if(offect<50){ offect+=10; } } } }
首先要在顶层布局中写上view的schemas:
<com.chxue8.view.VisualizerView android:id="@+id/mVisualizerView" android:layout_width="400dip" android:layout_height="200dip" android:layout_marginTop="40dip" android:layout_marginLeft="20dip" > </com.chxue8.view.VisualizerView>
VisualizerView mVisualizerView = (VisualizerView) findViewById(R.id.mVisualizerView); float[] pointFloat = null; pointFloat = new float[100]; pointFloat[0] = 0;//数组第一位哨兵 保存当前大小 pointFloat[1] = 97; //预留的值
当有新数据过来
int size = (int)pointFloat[0]; pointFloat[size++] = (float)spo_str; pointFloat[0] = size; //向前移动 if(size>=pointFloat.length){ for(int i=2;i<pointFloat.length;i++){ pointFloat[i-1] = pointFloat[i]; } size--; pointFloat[0] = size; } c++; //由于数据量太大了,没10个点取一个更新到图表上 if(c%10==0){ mVisualizerView.updateVisualizer(pointFloat); c = 0; }
效果图 :