公司要求做個心電圖,昨天就寫了下,原諒我懶得弄視頻了,看圖:
點擊開始開始繪製,繪製屏滿後,曲線向左移,點擊停止則停止繪製。
首先自定義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;i<refreshList.size();i++){
nowX = i* GRID_SMALL_WIDTH;
float dataValue = (float) refreshList.get(i);
if(dataValue>0){
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地址的,因爲非常簡單,還是傳一下吧,有更好想法的童鞋歡迎留言:
[email protected]:androidGL/WaveProject.git