Android自定義View——心電圖,曲線圖,波形圖

公司要求做個心電圖,昨天就寫了下,原諒我懶得弄視頻了,看圖:

點擊開始開始繪製,繪製屏滿後,曲線向左移,點擊停止則停止繪製。

首先自定義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

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章