实现心电图效果
自定义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 "读取错误,请检查文件名"; }
} `