接收數據實時更新的波狀曲線圖

  • 2019 年 10 月 7 日
  • 筆記

前面做了一個心電圖的demo 心電圖,結果發現那個心電圖是靜態的,是應用一啟動就已經畫好了的,整個頁面向左滑動而已

下面我改造了一下,寫了一個實時接收數據的動態心電圖,網上其他地方也有,但是沒有講到重點

我們先看看效果圖

很符合要求吧?只不過我沒有到達螢幕的最右邊就開始向左滑動是為了理解更方便

其實圖中的波狀曲線並不是在右邊一個一個的增加,而是數據增加,每次都全部重繪的一遍而已,看起來的效果就像右邊在增加一樣,這點要理解

先看程式碼

<?xml version="1.0" encoding="utf-8"?><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">      <View        android:layout_width="match_parent"        android:layout_height="300dp"        android:background="#000000" />      <com.jinke.path.PathView        android:id="@+id/pathView"        android:layout_width="match_parent"        android:layout_height="300dp" /></RelativeLayout>
import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;  import java.util.Timer;import java.util.TimerTask;  public class MainActivity extends AppCompatActivity {      private Timer timer;    private TimerTask timerTask;      @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final PathView pathView = findViewById(R.id.pathView);        //模擬實時數據        timer = new Timer();        timerTask = new TimerTask() {            @Override            public void run() {                Log.i("BLE", "11111111111111111");                pathView.setData(-100);            }        };        timer.schedule(timerTask, 0, 1000);    }      @Override    protected void onDestroy() {        super.onDestroy();        timerTask.cancel();        timer.cancel();        timerTask = null;        timer = null;    }}
import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.util.AttributeSet;import android.util.Log;import android.view.View;  import java.util.ArrayList;import java.util.List;  public class PathView extends View {    //畫筆    protected Paint paint;    //心電圖折線    protected Path path;    //自身的大小    private int width, height;      int tmpX;    //折現的顏色    private int lineColor = Color.parseColor("#76f112");      private List<Integer> list = new ArrayList<>();      public PathView(Context context) {        this(context, null);    }      public PathView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }      public PathView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        paint = new Paint();        path = new Path();    }      private void drawPath(Canvas canvas) {        Log.i("BLE", "drawPath");        // 重置path        path.reset();        paint.reset();        tmpX = 0;        path.moveTo(tmpX, height / 2);        //調節好每個波的X軸距離,盡量和滑動的速度保持一致        for (int i = 0; i < list.size(); i++) {            path.lineTo(tmpX + 50, height / 2 + list.get(i));            path.lineTo(tmpX + 100, height / 2);            tmpX += 100;        }        Log.i("BLE", "TMP=" + tmpX);        //設置畫筆style        paint.setStyle(Paint.Style.STROKE);        paint.setColor(lineColor);        paint.setStrokeWidth(5);        canvas.drawPath(path, paint);    }      @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        width = w;        height = h;        super.onSizeChanged(w, h, oldw, oldh);    }      @Override    protected void onDraw(Canvas canvas) {        Log.i("BLE", "onDraw");        drawPath(canvas);        //x軸滑動速度,一開始不滑動,當波形圖到達最右邊的時候開始滑動        if (list.size() > 15) {            scrollBy(1, 0);        }    }      public void setData(int data) {        Log.i("BLE", "");        //定期刪除歷史數據,防止圖片過長導致崩潰        if (list.size() > 30) {            for (int i = 0; i < 15; i++) {                list.remove(i);            }            scrollTo(0, 0);        }        list.add(data);        Log.i("BLE", "list-size=" + list.size());        postInvalidate();    }}

自定義View大家都會寫,關鍵是如何讓這個自定義View不停的動態重繪呢,網上沒有一個說明白的,我來告訴大家

重點:

1.MainActivity里的pathView.setData(-100);方法調用了PathView的setData方法,並傳入了更新的值

2.PathView調用了postInvalidate方法,觸發重繪

另外在開發中還遇到一個,就是當數據量比較大,View一直向左邊滑動,到了某一個時刻,波狀圖會消失,一片漆黑,看報錯原因,是因為滑動的太久,圖片拉伸太長導致,手機系統對於長圖有一個最長像素值,超過了這個值就會出問題

那麼我是如何解決的呢?

1.當數據到達一定量的時候,刪掉一部分歷史的數據

2.刪的同時通過scrollTo(0, 0)方法瞬間滑動最左邊

這樣就相當於一直在一個固定長度的View上繪圖,就不會出問題了,只不過會有少許的偏差,可以調節到滑動的速度和每個波圖的X軸距離儘可能的讓用戶感覺不到

GitHub地址:https://github.com/king1039/Path