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

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

  • 相关阅读:
    新建立了个集邮 Blog
    删除8848的mysearch
    VS2005的中国发布会
    免费的PDF生成工具
    FreeBASIC
    今天收到了WinZip发来的免费License
    简洁的 Bash 编程技巧
    benhuan039sblog.wordpress.20121111.xml_.txt
    新浪微博除掉推荐微博
    自制力也是一种力量
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/10892654.html
Copyright © 2011-2022 走看看