效果展示

实现心电图效果(此处为静态图片,动态演示还请移步码云或者网盘下载demo查看

自定义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<hSmallGridNum*2;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<hBigGridNum*2+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 "读取错误,请检查文件名";
            }




}

因为有的人可能git上不去这里放一个网盘链接好了

链接: 网盘链接

密码: fr84
附上码云地址

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐