Android 自制的一个简单的心电图pulseview

一个自己参考制作出来的心电图,原理很简单,先上图


上面部分是一个view用于显示局部心电图,下面是一个类似进度条的view用于显示全部心电图,当下面的黄色正方形被拖动,上面则会显示正方形所包含区域的局部心电图,起到一个预览的作用。

原理:现将所有数据传入下面的view画出来,再通过监测其ontouch事件,通过正方形的边长计算出其中包含的数据点,并将其取出传入上面的view进行绘图,下面上代码。

这是:上方那个view的代码

package com.healforce.healthapplication.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.healforce.healthapplication.R;

import java.util.ArrayList;
import java.util.List;

public class PulseView extends View
{

    private int XLength;
    private int XPoint;
    private int XScale = getResources().getDimensionPixelSize(R.dimen.x2);
    private int YLength = getResources().getDimensionPixelSize(R.dimen.x120);
    private int YPoint = getResources().getDimensionPixelSize(R.dimen.x100);
    private int YScale = getResources().getDimensionPixelSize(R.dimen.x2);

    private int MaxDataSize = XLength / XScale;
    private List<Integer> data;
    private int index;

    public PulseView(Context paramContext)
    {
        this(paramContext, null);
    }

    public PulseView(Context paramContext, AttributeSet paramAttributeSet)
    {
        this(paramContext, paramAttributeSet, 0);
    }

    public PulseView(Context context, AttributeSet attrs, int resId)
    {
        super(context, attrs, resId);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PulseView, resId, 0);
        XScale = typedArray.getDimensionPixelSize(0, getResources().getDimensionPixelSize(R.dimen.x2));
        YScale = typedArray.getDimensionPixelSize(1, getResources().getDimensionPixelSize(R.dimen.x20));

        typedArray.recycle();

        data = new ArrayList<>();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        XPoint = getResources().getDimensionPixelSize(R.dimen.x10);
        YPoint = height - getResources().getDimensionPixelSize(R.dimen.x10);
        XLength = width - getResources().getDimensionPixelSize(R.dimen.x20);
        YLength = height - getResources().getDimensionPixelSize(R.dimen.x20);

        MaxDataSize = (XLength / XScale);
        Log.i("PUlse",MaxDataSize+"");
    }

    public void addDataByPC80B(List<Integer> list) {
        if (data != null && data.size() > 0){
            data.clear();
        }
        for (int i = 0; i < list.size(); i++) {
            data.add(list.get(i));
            postInvalidate();
            if (data.size() >= MaxDataSize) {
                data.remove(0);
            }
        }
    }

    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        canvas.drawColor(getResources().getColor(R.color.light_gray));
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setAntiAlias(true);
        paint.setColor(getResources().getColor(R.color.yellow));
        //    y        canvas.drawLine(XPoint, YPoint - YLength, XPoint, YPoint, paint);

        //    画水平格子线
        for (int i = 0; i * YScale <= YLength; i++) {
            canvas.drawLine(XPoint, YPoint - i * YScale, XPoint + XLength, YPoint - i * YScale, paint);
        }
        //    x        canvas.drawLine(XPoint, YPoint, XPoint + XLength, YPoint, paint);
        //    画竖直格子线
        for (int j = 0; j * YScale <= XLength; j++) {
            canvas.drawLine(XPoint + j * YScale, YPoint, XPoint + j * YScale, YPoint - YLength, paint);
        }
        paint.setColor(Color.RED);
        paint.setStrokeWidth(2.0F);
        if (data.size() > 0) {
            //    画搏动折线
            for (int k = 1; k < data.size(); k++){
                canvas.drawLine(XPoint + (k - 1) * XScale, YPoint - data.get(k - 1), XPoint + k * XScale, YPoint - data.get(k), paint);
            }
            //    画刷新线
            paint.setColor(getResources().getColor(R.color.light_gray));
            paint.setStrokeWidth(5.0F);
            canvas.drawLine(index * XScale, YPoint - YLength, index * XScale, YPoint, paint);
        }
    }

    public void setData(List<Integer> list) {

        for (int i = 0;i< list.size(); i++){
            if (data.size() <= MaxDataSize){
                data.add(list.get(i));
            }else {
                if (index == MaxDataSize){
                    index = 0;
                }
                data.set(index, list.get(i));
                index ++ ;
            }
            postInvalidate();
        }
    }
}
主要调用setData的方法传入数据,即可完成绘制,关于绘制的相关知识,不懂的可以查找其他资料了解,这里就不多说,绘制的时候调用的postInvalidate方法主要是因为,我这个是运行在一个线程中,当不在线程中时可以使用 Invalidate也能达到效果。该控件可以实时传入数据绘制动态波形图,使用的是常见的刷新方法,放完一图刷一图,做的不是很好看,有待优化

接下来是下面的view的代码,很简单:

public class PC80bSectionView extends View {
    private List<Integer> data = new ArrayList<>();  //    数据源
    private float width;    //   控件宽
    private float height;   //   控件高
    private PulseView pulseView;
    //    随手指移动的正方形的中心
    private float rec_centerX;
    private float rec_centerY;
    private Rect rect = new Rect();

    public PC80bSectionView(Context context) {
        this(context,null,0);
    }

    public PC80bSectionView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public PC80bSectionView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

    }




    /**
     * 画随手指移动的正方形
     * @param canvas
     * @param paint
     */
    private void drawRect(Canvas canvas, Paint paint) {
        rec_centerY = (height / 2.0F);
        if (rec_centerX < height / 2.0F) {
            rec_centerX = (height / 2.0F);
        }

        if (rec_centerX > width - height / 2.0F) {
            rec_centerX = (width - height / 2.0F);
        }

        rect.left = ((int) (rec_centerX - height / 2.0F));
        rect.right = ((int) (rec_centerX + height / 2.0F));
        rect.top = ((int) (rec_centerY + height / 2.0F));
        rect.bottom = ((int) (rec_centerY - height / 2.0F));

        canvas.drawRect(rect.left, rect.top, rect.right, rect.bottom, paint);
    }

    /**
     * 画波形
     * @param canvas
     * @param paint
     */
    private void drawLine(Canvas canvas, Paint paint) {
        paint.setColor(Color.GREEN);
        if (this.data.size() > 1){
            for (int i = 1; i < data.size(); i++){
                //    4500表示每次心电仪传输过来的30秒数据的个数
                canvas.drawLine((i - 1) * (width / 4500.0F), height - (data.get(i - 1)),
                        i * (width / 4500.0F), height - data.get(i), paint);
            }
        }
    }

    public void postData(List<Integer> list) {
        data.addAll(list);
        postInvalidate();
    }

    public void clearData() {
        if ((data != null) && (data.size() > 1)){
            data.clear();
        }
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLACK);
        Paint paint = new Paint();
        paint.setColor(Color.YELLOW);
        paint.setStrokeWidth(2.0F);

        drawRect(canvas, paint);
        drawLine(canvas, paint);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        this.width = getMeasuredWidth();
        this.height = getMeasuredHeight();
    }

    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:

                rec_centerX = ((int) event.getX());
                invalidate();
                //    每次正方形发生移动计算出其中包含区间并将响应区间数据发送至pulseView显示
                if (pulseView != null) {
                    List<Integer> list = new ArrayList<>();

                    for (int i = 0; i < data.size(); i++) {
                        if ((i >= (int) (rect.left * 4500.0F / width)) && (i <= (int) (rect.right * 4500.0F / width))){
                            list.add(data.get(i) * 10);
                        }
                    }
                    pulseView.addDataByPC80B(list);
                }
        }
        return true;
    }

    public void setPulseView(PulseView pulseView) {
        this.pulseView = pulseView;
    }
}
核心代码都在ondraw里面,然后是ontouch时间,非常简单

这就是个人自制的一个简单的显示心电图的控件,本人新手想和大家分享一下,觉得有用就看看,要是觉得不好的就麻烦给点改进意见,初来乍到,请大家不吝赐教


  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值