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

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

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

咱們先看看效果圖android

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

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

先看代碼canvas

<?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不停的動態重繪呢,網上沒有一個說明白的,我來告訴你們微信

重點:app

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

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

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

那麼我是如何解決的呢?

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

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

這樣就至關於一直在一個固定長度的View上繪圖,就不會出問題了,只不過會有少量的誤差,能夠調節到滑動的速度和每一個波圖的X軸距離儘量的讓用戶感受不到

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

歡迎關注個人微信公衆號:安卓圈

相關文章
相關標籤/搜索