zoukankan      html  css  js  c++  java
  • 接收蓝牙数据实时更新的波状曲线图

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

    欢迎关注我的微信公众号:安卓圈

  • 相关阅读:
    svn command line tag
    MDbg.exe(.NET Framework 命令行调试程序)
    Microsoft Web Deployment Tool
    sql server CI
    VS 2010 One Click Deployment Issue “Application Validation did not succeed. Unable to continue”
    mshtml
    大厂程序员站错队被架空,只拿着五折工资!苟活和离职,如何选择?
    揭秘!Windows 为什么会蓝屏?微软程序员竟说是这个原因...
    喂!千万别忘了这个C语言知识!(~0 == -1 问题)
    Linux 比 Windows 更好,谁反对?我有13个赞成理由
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/10892654.html
Copyright © 2011-2022 走看看