接收蓝牙数据实时更新的波状曲线图

前面作了一个心电图的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

欢迎关注个人微信公众号:安卓圈

相关文章
相关标签/搜索