公司要求做个心电图,昨天就写了下,原谅我懒得弄视频了,看图:
点击开始开始绘制,绘制屏满后,曲线向左移,点击停止则停止绘制。
首先自定义View,WaveShowView,重写其onLayout,onDraw方法,注释写的很清楚了:
public class WaveShowView extends View {
private float mWidth = 0,mHeight = 0;//自身大小
private int mBackGroundColor = Color.BLACK;
private Paint mLinePaint;//画笔
private Paint mWavePaint;//心电图的折现
private Path mPath;//心电图的路径
private ArrayList refreshList = new ArrayList();//后加的数据点
private int row;//背景网格的行数和列数
//心电
private float MAX_VALUE = 20;
private float WAVE_LINE_STROKE_WIDTH = 2;
private int mWaveLineColor = Color.parseColor("#EE4000");//波形颜色
private float nowX,nowY;//目前的xy坐标
//网格
private final int GRID_SMALL_WIDTH = 10;//每一个网格的宽度和高度,包括线
private final int GRID_BIG_WIDTH = 50;//每一个大网格的宽度和高度,包括线
private int xSmallNum,ySmallNum,xBigNum,yBigNum;//小网格的横格,竖格,大网格的横格,竖格数量
private final int GRID_LINE_WIDTH=2;//网格的线的宽度
private int mWaveSmallLineColor = Color.parseColor("#092100");//小网格颜色
private int mWaveBigLineColor = Color.parseColor("#1b4200");//小网格颜色
public WaveShowView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public WaveShowView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w;
mHeight = h;
super.onSizeChanged(w, h, oldw, oldh);
}
private void init() {
mLinePaint = new Paint();
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setStrokeWidth(GRID_LINE_WIDTH);
mLinePaint.setAntiAlias(true);//抗锯齿效果
mWavePaint = new Paint();
mWavePaint.setStyle(Paint.Style.STROKE);
mWavePaint.setColor(mWaveLineColor);
mWavePaint.setStrokeWidth(WAVE_LINE_STROKE_WIDTH);
mWavePaint.setAntiAlias(true);//抗锯齿效果
mPath = new Path();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mWidth = getMeasuredWidth();//获取view的宽
mHeight = getMeasuredHeight();//获取view的高
row= (int) (mWidth/(GRID_SMALL_WIDTH));//获取行数
//小网格
xSmallNum = (int) (mHeight/GRID_SMALL_WIDTH);//横线个数=总高度/小网格高度
ySmallNum = (int) (mWidth/GRID_SMALL_WIDTH);//竖线个数=总宽度/小网格宽度
//大网格
xBigNum = (int) (mHeight/GRID_BIG_WIDTH);//横线个数
yBigNum = (int) (mWidth/GRID_BIG_WIDTH);//竖线个数
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制网格
drawGrid(canvas);
//绘制波形
drawWaveLine(canvas);
}
/**
* 画折线
* @param canvas
*/
private void drawWaveLine(Canvas canvas) {
if(null == refreshList || refreshList.size()<=0){
return;
}
mPath.reset();
mPath.moveTo(0f,mHeight/2);
for (int i = 0;i0){
if(dataValue>MAX_VALUE * 0.8){
dataValue = MAX_VALUE * 0.8f;
}
}else {
if(dataValue< -MAX_VALUE * 0.8){
dataValue = -MAX_VALUE * 0.8f;
}
}
nowY = mHeight/2 + dataValue *(mHeight/(MAX_VALUE*2));
mPath.lineTo(nowX,nowY);
}
canvas.drawPath(mPath, mWavePaint);
if(refreshList.size()>row){
refreshList.remove(0);
}
}
//画网格
private void drawGrid(Canvas canvas){
canvas.drawColor(mBackGroundColor);
//画小网格
mLinePaint.setColor(mWaveSmallLineColor);
//画横线
for(int i = 0;i < xSmallNum + 1;i++){
canvas.drawLine(0,i*GRID_SMALL_WIDTH,
mWidth, i*GRID_SMALL_WIDTH, mLinePaint);
}
//画竖线
for(int i = 0;i < ySmallNum+1;i++){
canvas.drawLine(i*GRID_SMALL_WIDTH,0,
i*GRID_SMALL_WIDTH,mHeight, mLinePaint);
}
//画大网格
mLinePaint.setColor(mWaveBigLineColor);
//画横线
for(int i = 0;i < xBigNum + 1;i++){
canvas.drawLine(0,i*GRID_BIG_WIDTH,
mWidth, i*GRID_BIG_WIDTH, mLinePaint);
}
//画竖线
for(int i = 0;i < yBigNum+1;i++){
canvas.drawLine(i*GRID_BIG_WIDTH,0,
i*GRID_BIG_WIDTH,mHeight, mLinePaint);
}
}
public void showLine(float line) {
refreshList.add(line);
postInvalidate();
}
//重置折现的坐标集合
public void resetCanavas() {
refreshList.clear();
}
}
然后写个使用的类,WaveUtil类,非常简单:
Timer是一种定时器,而TimerTask是一个抽象类,表示被Timer计划的任务,实现了Runnable接口。
public class WaveUtil {
private Timer timer;
private TimerTask timerTask;
/**
* 模拟源源不断的数据源
*/
public void showWaveData(final WaveShowView waveShowView){
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
waveShowView.showLine(new Random().nextFloat()*(40f)-20f);//取得是-20到20间的浮点数
}
};
//500表示调用schedule方法后等待500ms后调用run方法,50表示以后调用run方法的时间间隔
timer.schedule(timerTask,500,50);
}
/**
* 停止绘制波形
*/
public void stop(){
if(timer != null){
timer.cancel();
timer.purge();
timer = null;
}
if(null != timerTask) {
timerTask.cancel();
timerTask = null;
}
}
}
最后在activity页面调用,也非常简单,为了避免内存泄漏,退出activity时必须停止绘制:
//开始绘制波形
public void start(View view) {
WaveShowView waveShowView = findViewById(R.id.waveview);
waveUtil.showWaveData(waveShowView);
}
//停止绘制波形
public void stop(View view) {
waveUtil.stop();
}
其实不用上传git地址的,因为非常简单,还是传一下吧,有更好想法的童鞋欢迎留言:
https://github.com/androidGL/WaveProject.git