在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; 

    }


效果图 :

 在android中实现动态跑动的图表实现方法

 

 

你可能感兴趣的:(android)