安卓实现ECG心电图功能
效果展示![实现心电图效果(此处为静态图片,动态演示还请移步github或者网盘下载demo查看)](https://img-blog.csdnimg.cn/1c7d51369f364877b50da0f70baa6907.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5L
·
效果展示
实现心电图效果(此处为静态图片,动态演示还请移步码云或者网盘下载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
附上码云地址
更多推荐
已为社区贡献2条内容
所有评论(0)