日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android如何自定义一个心电图控件?

發布時間:2023/12/3 Android 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android如何自定义一个心电图控件? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

摘要:在我們的日常生活中,通常需要用儀器測量心率數據,來觀測身體是否在一個健康的范圍之內, 下面的心率圖就是用一個胎心儀測量的一個寶寶心率圖。
自定義控件如下圖所示:
畫好這樣的一個心電圖視圖需要自定義一個控件具體步驟如下:
一 自定義屬性

  • 在attrs.xml下自定義如下屬性,在我們使用此自定義控件的時候,可以根據需求改變樣式。
  • <declare-styleable name="chartView"><!-- xy坐標軸顏色 --><attr name="xylinecolor" format="color" /><!-- xy坐標軸寬度 --><attr name="xylinewidth" format="dimension" /><!-- xy坐標軸文字顏色 --><attr name="xytextcolor" format="color" /><!-- xy坐標軸文字大小 --><attr name="xytextsize" format="dimension" /><!-- 折線圖中折線的顏色 --><attr name="linecolor" format="color" /><!-- x軸各個坐標點水平間距 --><attr name="interval" format="dimension" /><!-- 背景顏色 --><attr name="bgcolor" format="color" /><!--是否在ACTION_UP時,根據速度進行自滑動,建議關閉,過于占用GPU--><attr name="isScroll" format="boolean" /></declare-styleable>
  • 使用自定義屬性
  • TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.chartView, defStyleAttr, 0);int count = array.getIndexCount();for (int i = 0; i < count; i++) {int attr = array.getIndex(i);switch (attr) {case R.styleable.chartView_xylinecolor://xy坐標軸顏色xylinecolor = array.getColor(attr, xylinecolor);break;case R.styleable.chartView_xylinewidth://xy坐標軸寬度xylinewidth = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xylinewidth, getResources().getDisplayMetrics()));break;case R.styleable.chartView_xytextcolor://xy坐標軸文字顏色xytextcolor = array.getColor(attr, xytextcolor);break;case R.styleable.chartView_xytextsize://xy坐標軸文字大小xytextsize = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, xytextsize, getResources().getDisplayMetrics()));break;case R.styleable.chartView_linecolor://折線圖中折線的顏色linecolor = array.getColor(attr, linecolor);break;case R.styleable.chartView_interval://x軸各個坐標點水平間距interval = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, interval, getResources().getDisplayMetrics()));break;case R.styleable.chartView_bgcolor: //背景顏色bgcolor = array.getColor(attr, bgcolor);break;case R.styleable.chartView_isScroll://是否在ACTION_UP時,根據速度進行自滑動isScroll = array.getBoolean(attr, isScroll);break;}}array.recycle();

    二 繪制圖形

  • 繪制X軸以及上方的水平虛線,水平軸的時間文字及描點。
  • //繪制X軸坐標canvas.drawLine(xOri, yOri + xylinewidth / 2, width, yOri + xylinewidth / 2, xyPaint);//繪制x軸刻度for (int i = 0; i < xValue.size(); i++) {float x = xInit + interval * i;if (i == 0 && x - interval >= xOri) {String text = TimeUtil.getChartTime(0);Rect rect = getTextBounds(text, xyTextPaint);canvas.drawText(text, 0, text.length(), x - interval - rect.width() / 2, yOri + xylinewidth + dpToPx(4) + rect.height(), xyTextPaint);canvas.drawCircle(xOri, yOri, radiu, linePaint);}if (x >= xOri) {//只繪制從原點開始的區域xyTextPaint.setColor(xytextcolor);canvas.drawLine(x, yOri - yLength * (yValue.size() - 1) + xylinewidth / 2, x, yOri, (i + 1) % 3 == 0 ? xyPaint : xyredPaint);//繪制X軸文本if ((i + 1) % 3 == 0) {String text = TimeUtil.getChartTime((i + 1) * perLengTime);Rect rect = getTextBounds(text, xyTextPaint);canvas.drawText(text, 0, text.length(), x - rect.width() / 2 - dpToPx(2), yOri + xylinewidth + dpToPx(4) + rect.height(), xyTextPaint);canvas.drawCircle(x, yOri, radiu, linePaint);}}}
  • 繪制Y軸以及上方的水平虛線,水平軸的心率數值文字及描點。
  • canvas.drawLine(xOri - xylinewidth / 2, yOri - yLength * (yValue.size() - 1), xOri - xylinewidth / 2, yOri, xyPaint);for (int i = 0; i < yValue.size(); i++) {//繪制Y軸刻度canvas.drawLine(xOri, yOri - yLength * i + xylinewidth / 2, width, yOri - yLength * i + xylinewidth / 2, xyPaint);canvas.drawCircle(xOri, yOri - yLength * i, radiu, linePaint);if (i > 0) {canvas.drawLine(xOri, yOri - yLength * i + xylinewidth / 2 + 1.0f / 3 * yLength, width, yOri - yLength * i + xylinewidth / 2 + 1.0f / 3 * yLength, xyredPaint);canvas.drawLine(xOri, yOri - yLength * i + xylinewidth / 2 + 2.0f / 3 * yLength, width, yOri - yLength * i + xylinewidth / 2 + 2.0f / 3 * yLength, xyredPaint);}xyTextPaint.setColor(xytextcolor);//繪制Y軸文本String text = yValue.get(i) + "";Rect rect = getTextBounds(text, xyTextPaint);canvas.drawText(text, 0, text.length(), xOri - xylinewidth - dpToPx(3) - rect.width(), yOri - yLength * i + rect.height() / 2, xyTextPaint);int length = xValue.size() / 12;if (length > 0) {for (int j = 1; j <= length; j++) {float x1 = xInit + interval * j * 12;if (x1 > xOri + interval * 6)canvas.drawText(text, 0, text.length(), x1 - interval - rect.width() - dpToPx(3), yOri - yLength * i + rect.height() / 2, xyTextPaint);}}}
  • 繪制心率單位
  • private void drawUnit(Canvas canvas, int yLength) {xyTextPaint.setTextSize(dpToPx(6));String text = "FHR/bpm";Rect rect = getTextBounds(text, xyTextPaint);//第一豎排的單位canvas.drawText("FHR/bpm", 0, text.length(), xOri - xylinewidth - dpToPx(3) - rect.width(), yOri - yLength * (1.0f * (yValue.size() - 1) / 2) + rect.height() / 2, xyTextPaint);//后面豎排的單位int length = xValue.size() / 12;if (length > 0) {for (int j = 1; j <= length; j++) {float x1 = xInit + interval * j * 12;if (x1 > xOri + interval * 6)canvas.drawText(text, 0, text.length(), x1 - interval - rect.width() - dpToPx(3), yOri - yLength * (1.0f * (yValue.size() - 1) / 2) + rect.height() / 2, xyTextPaint);}}}xyTextPaint);
  • 繪制正常綠色區域(120-160心率)
  • RectF f = new RectF();f.top = yOri - yLength * (4 + 1.0f / 3);f.bottom = yOri - yLength * 3;f.left = xOri;f.right = width;canvas.drawRect(f, okAreaPaint);
  • 繪制折線圖
  • /*** 繪制折線* @param canvas*/private void drawBrokenLine(Canvas canvas) {//perLengTime初始為5s 如果value的長度超過一分鐘 那么需要改變perlengTime為20sif (value.size() < 2) return;linePaint.setStyle(Paint.Style.STROKE);linePaint.setColor(linecolor);//繪制折線Path path = new Path();float x = xInit - interval + interval * (betweemTime + base) / perLengTime;float y = yOri - yOri * (1 - 0.1f) * (value.get(0) - yValue.get(0)) / (yValue.get(yValue.size() - 1) - yValue.get(0));path.moveTo(x, y);for (int i = 1; i < value.size(); i += 3) {x = getXLength(i);y = getYLength(i);if (isContinuous) {setContinuousPath(i, path, x, y);} else {setNoContinuousPath(i, path, x, y);}}linePaint.setStrokeWidth(dpToPx(1f));canvas.drawPath(path, linePaint);}
  • 最后一個心率動態打點
  •  /*** 最后一個心率點* @param canvas*/private void drawSelectPointLinePoint(Canvas canvas) {if (value.size() == 0) return;int position = value.size() - 1;float dp7 = dpToPx(5);float x = xInit - interval + 1.0f * interval * ((position + 1) * betweemTime + base) / perLengTime;float y = yOri - yOri * (1 - 0.1f) * (value.get(position) - yValue.get(0)) / (yValue.get(yValue.size() - 1) - yValue.get(0));linePaint.setStyle(Paint.Style.FILL);linePaint.setColor(markColor);linePaint.setStrokeWidth(dpToPx(1));canvas.drawCircle(x, y, dp7, linePaint);linePaint.setStrokeWidth(dpToPx(2));canvas.drawLine(x, 0, x, getHeight(), linePaint);}

    三.處理滑動事件和點擊事件
    根據當前手勢滑動的距離來動態更新繪制心率圖,根據手指按下和松開的xy方向的距離來判斷點擊事件(這個可以進行橫豎屏切換)具體代碼如下:

    private float startX, x1, y1, x2, y2;boolean isTouch;boolean isClick;//是否正在滑動private boolean isScrolling = false;@Overridepublic boolean onTouchEvent(MotionEvent event) {if (isScrolling)return super.onTouchEvent(event);this.getParent().requestDisallowInterceptTouchEvent(true);//當該view獲得點擊事件,就請求父控件不攔截事件obtainVelocityTracker(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:startX = event.getX();isClick = true;x1 = event.getX();y1 = event.getY();break;case MotionEvent.ACTION_MOVE:if (interval * xValue.size() > width - xOri) {//當期的寬度不足以呈現全部數據float dis = event.getX() - startX;startX = event.getX();if (xInit + dis < minXInit) {xInit = minXInit;} else if (xInit + dis > maxXInit) {xInit = maxXInit;} else {xInit = xInit + dis;}invalidate();}isClick = false;break;case MotionEvent.ACTION_UP:if (event.getX() + getLeft() < getRight() && event.getY() + getTop() < getBottom()) {x2 = event.getX();y2 = event.getY();if (Math.abs(x1 - x2) < 6 && Math.abs(y1 - y2) < 6) {if (onChartClickListener != null)onChartClickListener.onChartClick();return false;// 距離較小,當作click事件來處理}}scrollAfterActionUp();this.getParent().requestDisallowInterceptTouchEvent(false);recycleVelocityTracker();break;case MotionEvent.ACTION_CANCEL:this.getParent().requestDisallowInterceptTouchEvent(false);recycleVelocityTracker();break;}return true;}

    手指抬起后的滑動處理,這個比較耗GPU性能,建議關閉

    /*** 手指抬起后的滑動處理*/private void scrollAfterActionUp() {if (!isScroll)return;final float velocity = getVelocity();float scrollLength = maxXInit - minXInit;if (Math.abs(velocity) < 10000)//10000是一個速度臨界值,如果速度達到10000,最大可以滑動(maxXInit - minXInit)scrollLength = (maxXInit - minXInit) * Math.abs(velocity) / 10000;ValueAnimator animator = ValueAnimator.ofFloat(0, scrollLength);animator.setDuration((long) (scrollLength / (maxXInit - minXInit) * 1000));//時間最大為1000毫秒,此處使用比例進行換算animator.setInterpolator(new DecelerateInterpolator());animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {float value = (float) valueAnimator.getAnimatedValue();if (velocity < 0 && xInit > minXInit) {//向左滑動if (xInit - value <= minXInit)xInit = minXInit;elsexInit = xInit - value;} else if (velocity > 0 && xInit < maxXInit) {//向右滑動if (xInit + value >= maxXInit)xInit = maxXInit;elsexInit = xInit + value;}invalidate();}});animator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animator) {isScrolling = true;}@Overridepublic void onAnimationEnd(Animator animator) {isScrolling = false;}@Overridepublic void onAnimationCancel(Animator animator) {isScrolling = false;}@Overridepublic void onAnimationRepeat(Animator animator) {}});animator.start();}/*** 獲取速度** @return*/private float getVelocity() {if (velocityTracker != null) {velocityTracker.computeCurrentVelocity(1000);return velocityTracker.getXVelocity();}return 0;}

    四 結語
    整個心率圖的自定義控件就已經結束了,然后通過設置xy軸的數據,以及具體的折線圖數據就可以顯示一個非常完美的折線圖了。

    總結

    以上是生活随笔為你收集整理的Android如何自定义一个心电图控件?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。