安卓开发实现ECG心电图效果

136 阅读4分钟

实现心电图效果 112233.gif

自定义view

`public class MyBG extends View {

private Paint mPaint;
//View的宽度
private int view_width;
//View的高度
private int view_height;
//基准线 在View的垂直居中的位置
protected int baseLine;
//小格子的宽度
private int smallGrid = 20;
//大个字的宽度 一个大格子里面包含5个小格子
private int bigGrid = smallGrid * 5;
//小格子的线的颜色
private int smallGridColor = Color.parseColor("#ffc0cb");
//大格子的线的颜色
private int bigGridColor = Color.parseColor("#ffc0cb");
//View的背景颜色
private int BGColor = Color.WHITE;


public MyBG(Context context) {
    super(context);
    init();
    setBackgroundColor(BGColor);

}

public MyBG(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init();
    setBackgroundColor(BGColor);
}
/**
 * 初始化
 */
private void init() {
    mPaint = new Paint();
    mPaint.setStrokeWidth(2);
    mPaint.setAntiAlias(true);
}


@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    view_width = w;
    view_height = h;
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {
    drawGridBackground(canvas);
}


/**
 * 绘制心电图背景格子
 * @param canvas
 */
private void drawGridBackground(Canvas canvas) {
    //画小格子
    //注意,小格子横线的个数
    int hSmallGridNum = view_height/smallGrid;
    mPaint.setColor(smallGridColor);
    mPaint.setStrokeWidth(1);
    //取余,得到多的不足smallGrid高度的部分

// int a = view_height % smallGrid; //这里画的横线部分 for(int i = 1;i<hSmallGridNum2;i++){ canvas.drawLine(0,//起点x i * smallGrid,//起点y view_width,//终点x i * smallGrid,//终点Y mPaint); } //这里获取小格子竖线有多少 int sSmallGridNum = view_width/smallGrid; for(int i = 0;i<sSmallGridNum + 1;i++) { canvas.drawLine(i * smallGrid, 0, i * smallGrid, view_height, mPaint); } //下面画大格子 mPaint.setStrokeWidth(2); mPaint.setColor(bigGridColor); //得到大格子的个数,实际上这里只是拿到了上部分的大格子个数 int hBigGridNum = view_height/bigGrid; //这里画的横线部分 for(int i = 0;i<hBigGridNum2+2;i++){ if(i == hBigGridNum/2){ //基准线的位置 baseLine = i * bigGrid; //中间基准线 mPaint.setColor(Color.RED); }else { mPaint.setColor(bigGridColor); } canvas.drawLine(0,//起点x i * bigGrid ,//起点y view_width,//终点x i * bigGrid,//终点Y mPaint); } //画大格子竖线 int sBigGridNum = view_width / bigGrid; for (int i = 0;i <sBigGridNum + 1;i++){ canvas.drawLine(i * bigGrid, 0, i * bigGrid, view_height, mPaint); }

}

} `

`public class MyData extends View {

private List<Float> datas = new ArrayList<>();
private Paint mPaint;
private Path mPath;
//心电图曲线的颜色
private int color = Color.parseColor("#000000");
//心电图的宽度
private float line_width = 4f;
private int view_width;
private int view_height;
private int baseLine;//基准线
private int smallGridWith = 15;
private int bigGridWidth = smallGridWith * 5;
private int bigGridNum;
//表示每个小格子放五个数据
private int dataNumber = 5;

//屏幕能够显示的所有的点的个数 注意这个值设置为int会导致这个数值不准确
private float maxSize = 0;

public MyData(Context context) {
    super(context);
    init();
    setBackgroundColor(ContextCompat.getColor(context,android.R.color.transparent));
}
public MyData(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init();
    setBackgroundColor(ContextCompat.getColor(context,android.R.color.transparent));
}

/**
 * 这个方法可以每隔格子放的数据数量
 * @param dataNumber
 */
public void setDataNumber(int dataNumber) {
    this.dataNumber = dataNumber;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    view_width = w;
    view_height = h;
    bigGridNum = view_height / bigGridWidth;
    baseLine = bigGridNum /2 * bigGridWidth;
    maxSize =  view_width*(1.0f) / (smallGridWith / (dataNumber*1.0f));//125个数据占用为5个大格子,5个大格子有25个小格子,所以每个小格子放5个数据
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
}
private boolean isDrawFinish = false;
@Override
protected void onDraw(Canvas canvas) {

// super.onDraw(canvas); //清除路径 mPath.reset(); if(datas != null && datas.size()>0){ mPath.moveTo(0,change(datas.get(0))); //1 s更新125个数据,125个数据占用为5个大格(25个小格) //1个小格子为5个数据 1个数据为16/5小格 1小格的宽度为16 1个数据的宽度是16/5 for (int i = 0;i<datas.size();i++){ mPath.lineTo(i * smallGridWith /dataNumber,change(datas.get(i))); } canvas.drawPath(mPath,mPaint); } isDrawFinish = true; } /** * 添加数据 * @param data */ public void addData(Float data){ if(datas.size() > maxSize){ //如果这个集合大于maxSize(即表示屏幕上所能显示的点的个数)个点,那么就把第一个点移除 // Log.d(TAG, "addData: "+maxSize); datas.remove(0); } datas.add(data); if(!isDrawFinish){ return; } //这个方法会重新调用onDraw()方法 这个方法用在主线程 invalidate();

}
/**
 * 把数据转化为对应的坐标  1大格表示的数据值为0.5毫伏,1毫伏= 200(数据) 1大格表示的数据 = 0.5 *200 1小格表示的数据 = 0.5*200/5 = 20
 * 1 小格的数据 表示为20 1小格的高度为16
 * @param data
 * @return
 */
private float change(Float data){
    return (float) (-1.0) * data / 20 * smallGridWith + baseLine;
}

private void init() {
    mPaint = new Paint();
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setAntiAlias(true);
    mPaint.setColor(color);
    mPaint.setStrokeWidth(line_width);
    mPath = new Path();
}

} `

`// 调用 private static ScheduledExecutorService scheduledExecutorService;

private void times() {
    final int index = -1;
    final AtomicInteger atomicInteger = new AtomicInteger(index);
    if (scheduledExecutorService != null) {
        scheduledExecutorService.shutdownNow();
    }
    scheduledExecutorService = new ScheduledThreadPoolExecutor(10);
    scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            try {
                final int mark = atomicInteger.incrementAndGet();

// Log.e("====", mark+">>>"+allDatas.get(mark) + ""); if (mark >= allDatas.size()) { scheduledExecutorService.shutdownNow(); return; } runOnUiThread(new Runnable() { @Override public void run() { myData.addData(allDatas.get(mark)); // } }); } catch (Exception e) { } } }, 200, 8, TimeUnit.MILLISECONDS); //延迟时间,间隔时间,单位 }

//因为是demo所以数据源读取的是取出的一部分数据放入txt

//根据需求处理 private void changeData(String starCareData) { allDatas.clear(); for (int i = 0; i < 5; i++) { allDatas.add(0f); } String[] lines = starCareData.replace(" ", "").split("\n"); //100ms一行 一行50个 StringBuffer sb = new StringBuffer(); for (int i = 0; i < lines.length; i++) { int start = lines[i].indexOf(":") + 1; String value = lines[i].substring(start); sb.append(value).append(",");

    }
    sb.deleteCharAt(sb.lastIndexOf(","));
    String[] valueList = sb.toString().split(",");
    for (int j = 0; j < valueList.length; j+=4) {
        float temp = Float.parseFloat(valueList[j]);
        float data = temp / 1000000.0f / 0.1f * 40; //除以0.1是将数据转换为页面单位,扩大40倍 (根据设备提供的数据来)
        allDatas.add(data);
    }

}

//文件读取

public class ReadAssetsFileUtils {

/**
 * 读取assets下的txt文件,返回utf-8 String

// * @param context * @param fileName 不包括后缀 * @return */ public static String readAssetsTxt(Context context, String fileName){ try {

        InputStream is = context.getAssets().open(fileName+".txt");
        int size = is.available();
        // Read the entire asset into a local byte buffer.
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();
        // Convert the buffer into a string.
        String text = new String(buffer, "utf-8");
        // Finally stick the string into the text view.
        return text;
    } catch (IOException e) {
        // Should never happen!

// throw new RuntimeException(e); e.printStackTrace(); } return "读取错误,请检查文件名"; }

} `