Android——ECG心电图的绘制实现
Posted 化作孤岛的瓜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android——ECG心电图的绘制实现相关的知识,希望对你有一定的参考价值。
在上篇Android——ECG心电图的绘制实现博客中,实现了心电图的数据展示绘制。
在之后又新增了 心电图的自动滑动展示 与 实时绘制 功能。效果如下:
自动滑动展示
实时绘制(这里用到了一个timer不断添加数据)
一、自动滑动展示 实现
实现思路:
通过开启定时器实现下标scrollIndex不断增加,以此来计算展示数据的开始下标scrollStartIndex与结束下标scrollEndIndex,来获得一段数据data[]中的展示数据,该段数据刚好填满view的宽度(按比例填满),然后不断的更细视图,实现视觉上的滑动效果(View实际上没有滑动)。如图所示:
代码实现:
首先在initData()初始化数据的时候,调用startScrollTimer()方法,开启一个timer,去不断的更新下标:
private fun startScrollTimer()
timer = Timer()
timerTask = object : TimerTask()
override fun run()
if (scrollIndex < data!!.size)
scrollIndex++
else
scrollIndex = 0
timer!!.schedule(timerTask, 0, 50)
然后在ondraw中,进行具体的绘制:
// 绘制心电滚动视图
private fun drawHeartScroll(canvas: Canvas)
if (data == null || data!!.size == 0)
return
paint!!.reset()
path!!.reset()
paint!!.style = Paint.Style.STROKE
paint!!.color = Color.parseColor("#31CE32")
paint!!.strokeWidth = mGridLinestrokeWidth
paint!!.isAntiAlias = true
path!!.moveTo(0f, mHeight / 2)
var scrollStartIndex = 0
var scrollEndIndex = 0
scrollEndIndex = scrollIndex
scrollStartIndex = scrollEndIndex - intervalNumHeart
if (scrollStartIndex < 0)
scrollStartIndex = 0
var nowX: Float
var nowY: Float
for (i in scrollStartIndex until scrollEndIndex)
nowX = (i - scrollStartIndex) * intervalRowHeart
var dataValue = data!![i]
if (dataValue > 0)
if (dataValue > MAX_VALUE * 0.8f)
dataValue = MAX_VALUE * 0.8f
else
if (dataValue < -MAX_VALUE * 0.8f)
dataValue = -(MAX_VALUE * 0.8f)
nowY = mHeight / 2 - dataValue * intervalColumnHeart
path!!.lineTo(nowX, nowY)
LogUtils.d("drawHeartScroll $nowX $nowY")
canvas.drawPath(path!!, paint!!)
postInvalidate()
其中,前半部分是对数据下标的整理,后半部分是对整理的data数据进行实时展示。
二、实时绘制刷新refresh 实现
实现思路
这个就比上一个复杂多了。通过showLine(float float) 方法,让外界能输入数据并动态展示在心电图上,也就是说需要实现一个动态递增的Arraylist,然后在具体的绘制中,实现如下所示的数据结构:
第1次添加 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
第2次添加 1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
第3次添加 1 , 2 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
第4次添加 1 , 2 , 3 , 4 , 0 , 0 , 0 , 0 , 0 , 0 ,
第5次添加 1 , 2 , 3 , 4 , 5 , 0 , 0 , 0 , 0 , 0 ,
第6次添加 1 , 2 , 3 , 4 , 5 , 6 , 0 , 0 , 0 , 0 ,
第7次添加 1 , 2 , 3 , 4 , 5 , 6 , 7 , 0 , 0 , 0 ,
第8次添加 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 0 , 0 ,
第9次添加 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ,
第10次添加 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,
第11次添加 11 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,
第12次添加 11 , 12 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,
第13次添加 11 , 12 , 13 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,
第14次添加 11 , 12 , 13 , 14 , 5 , 6 , 7 , 8 , 9 , 10 ,
第15次添加 11 , 12 , 13 , 14 , 15 , 6 , 7 , 8 , 9 , 10 ,
第16次添加 11 , 12 , 13 , 14 , 15 , 16 , 7 , 8 , 9 , 10 ,
第17次添加 11 , 12 , 13 , 14 , 15 , 16 , 17 , 8 , 9 , 10 ,
第18次添加 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 9 , 10 ,
第19次添加 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 10 ,
第20次添加 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
第21次添加 21 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
第22次添加 21 , 22 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
第23次添加 21 , 22 , 23 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,
第24次添加 21 , 22 , 23 , 24 , 15 , 16 , 17 , 18 , 19 , 20 ,
第25次添加 21 , 22 , 23 , 24 , 25 , 16 , 17 , 18 , 19 , 20 ,
第26次添加 21 , 22 , 23 , 24 , 25 , 26 , 17 , 18 , 19 , 20 ,
第27次添加 21 , 22 , 23 , 24 , 25 , 26 , 27 , 18 , 19 , 20 , ....(后面省略)
可以看到要位置一个总长度固定的数据,但是随着数据的增加新的数据是从左往右进行刷新的(对应刷新心电图数据的刷新方式),实现了该结构之后,再去做数据展示就可以实现心电图的刷新绘制了。
为此我专门写了一个测试类去测试:
public class TestClass
private static List<Float> refreshList = new ArrayList<>();
private static float[] data; //一排显示的数据 一排10个
private static int intervalNumHeart = 10;
private static int showIndex;
public static void main(String[] args)
data = new float[intervalNumHeart];
for (int i = 1; i < 100; i++)
refreshList.add((float) i);
drawHeartRefresh();
private static void drawHeartRefresh()
int nowIndex = refreshList.size(); //当前长度
if (nowIndex < intervalNumHeart)
showIndex = nowIndex - 1;
else
showIndex = (nowIndex - 1) % intervalNumHeart;
for (int i = 0; i < intervalNumHeart; i++)
if (i > refreshList.size() - 1)
break;
if (nowIndex <= intervalNumHeart)
data[i] = refreshList.get(i);
else
int times = (nowIndex - 1) / intervalNumHeart;
int temp = times * intervalNumHeart + i;
if (temp < nowIndex)
data[i] =
refreshList.get(temp);
logdata();
private static void logdata()
String str = "";
for (float temp : data)
int tempInt = (int) temp;
str += tempInt + " , ";
Log( "第" +(refreshList.size()) + "次添加 " + str + " " );
private static void Log(String txt)
System.out.println(txt);
代码实现
一样分为两个部分,前半部分实现该结构,后半部分进行具体的绘制:
private fun drawHeartRefresh(canvas: Canvas)
paint!!.reset()
path!!.reset()
paint!!.style = Paint.Style.STROKE
paint!!.color = Color.parseColor("#31CE32")
paint!!.strokeWidth = mGridLinestrokeWidth
paint!!.isAntiAlias = true
path!!.moveTo(0f, mHeight / 2)
val nowIndex = if (refreshList == null) 0 else refreshList!!.size //当前长度
if (nowIndex == 0)
return
if (nowIndex < intervalNumHeart)
showIndex = nowIndex - 1
else
showIndex = (nowIndex - 1) % intervalNumHeart
for (i in 0 until intervalNumHeart)
if (i > refreshList!!.size - 1)
break
if (nowIndex <= intervalNumHeart)
data!![i] = refreshList!![i]
else
val times = (nowIndex - 1) / intervalNumHeart
val temp = times * intervalNumHeart + i
if (temp < nowIndex)
data?.set(i, refreshList!![temp])
logdata()
//绘制出data
var nowX: Float
var nowY: Float
for (i in data!!.indices)
nowX = i * intervalRowHeart
var dataValue = data!![i]
if (dataValue > 0)
if (dataValue > MAX_VALUE * 0.8f)
dataValue = MAX_VALUE * 0.8f
else
if (dataValue < -MAX_VALUE * 0.8f)
dataValue = -(MAX_VALUE * 0.8f)
nowY = mHeight / 2 - dataValue * intervalColumnHeart
if (i - 1 == showIndex)
path!!.moveTo(nowX, nowY)
else
path!!.lineTo(nowX, nowY)
canvas.drawPath(path!!, paint!!)
近期在把所有写过的自定义view(实用性较强的)整理成一个开源框架,Github地址:
https://github.com/jiangzhengnan/UI#ngui
gradle依赖:
compile 'ng.ngui.ngbase:nguilib:0.0.1'
以上是关于Android——ECG心电图的绘制实现的主要内容,如果未能解决你的问题,请参考以下文章