自定义View血压

编程入门 行业动态 更新时间:2024-10-08 08:25:27

<a href=https://www.elefans.com/category/jswz/34/1771438.html style=自定义View血压"/>

自定义View血压

使用
var bpList = mutableListOf()

av_specific_bp.setBPData(this.bpList)

     <com.oplayer.orunningplus.view.HomePageBPVIewandroid:id="@+id/av_specific_bp"android:layout_width="match_parent"android:layout_height="100dp"android:layout_marginTop="60dp" />

HomePageBPVIew.kt

package com.example.myapplication
import android.app.Service
import android.content.Context
import android.graphics.*
import android.text.TextPaint
import android.util.AttributeSet
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.widget.OverScroller
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewCompat
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import java.text.SimpleDateFormat
import java.util.*class HomePageBPVIew(private var mContext: Context,attrs: AttributeSet?,defStyleAttr: Int
) : View(mContext, attrs, defStyleAttr) {private var mBound: Rect? = nullprivate var textStart = 0fprivate var mHeight = 0private var mWidth = 0private var ecgList: List<BPBean> = ArrayList()private val verticalWidth = 100fprivate var chartWidth=0f //表的总宽度,除过外间距 = 0fprivate val outSpace = verticalWidth // 柱子与纵轴的距离private var startChart = verticalWidth //柱子开始的横坐标private var interval=0f //柱子之间的间隔 = 0fprivate var barWidth=0f //柱子的宽度 = 0fprivate val bottomHeight = 100f //底部横坐标高度private val maxValue = "230" //默认最大值private val middleValue = "1"private val paddingTop = 20fprivate val noDataPaint: Paint? = nullprivate var textXpaint: TextPaint? = nullprivate var linePaint: Paint? = nullprivate val textColor = UIUtils.getColor(R.color.gray_date_text_color)private val bgColor = ContextCompat.getColor(mContext,R.color.colorPrimary)private val mDuriation = 3000private var textYpaint: TextPaint? = null//    private ChartAnimator mAnimator;private var mGestureDetector: GestureDetectorCompat? = nullprivate var mScroller: OverScroller? = nullprivate var yBackgroundPaint: Paint? = nullprivate var weight = 0fprivate var height = 0fenum class Direction {NONE, LEFT, RIGHT, VERTICAL}//正常滑动方向private var mCurrentScrollDirection = Direction.NONE//快速滑动方向private var mCurrentFlingDirection = Direction.NONEprivate val mHorizontalFlingEnabled = trueprivate val mCurrentOrigin = PointF(0f, 0f)private val mScrollDuration = 250//滑动速度private val mXScrollingSpeed = 1fprivate var mMinimumFlingVelocity = 0///// 滑动相关///private val mGestureListener: SimpleOnGestureListener = object : SimpleOnGestureListener() {//手指按下override fun onDown(e: MotionEvent): Boolean {goToNearestBar()return true}//有效的滑动override fun onScroll(e1: MotionEvent,e2: MotionEvent,distanceX: Float,distanceY: Float): Boolean {when (mCurrentScrollDirection) {Direction.NONE ->                     // 只允许在一个方向上滑动mCurrentScrollDirection = if (Math.abs(distanceX) > Math.abs(distanceY)) {if (distanceX > 0) {Direction.LEFT} else {Direction.RIGHT}} else {Direction.VERTICAL}Direction.LEFT ->                     // Change direction if there was enough change.if (Math.abs(distanceX) > Math.abs(distanceY) && distanceX < 0) {mCurrentScrollDirection =Direction.RIGHT}Direction.RIGHT ->                     // Change direction if there was enough change.if (Math.abs(distanceX) > Math.abs(distanceY) && distanceX > 0) {mCurrentScrollDirection =Direction.LEFT}}when (mCurrentScrollDirection) {Direction.LEFT, Direction.RIGHT -> {mCurrentOrigin.x -= distanceX * mXScrollingSpeedViewCompat.postInvalidateOnAnimation(this@HomePageBPVIew)}}return true}//快速滑动override fun onFling(e1: MotionEvent,e2: MotionEvent,velocityX: Float,velocityY: Float): Boolean {if (mCurrentFlingDirection == Direction.LEFT && !mHorizontalFlingEnabled ||mCurrentFlingDirection == Direction.RIGHT && !mHorizontalFlingEnabled) {return true}mCurrentFlingDirection = mCurrentScrollDirectionmScroller!!.forceFinished(true)when (mCurrentFlingDirection) {Direction.LEFT, Direction.RIGHT -> mScroller!!.fling(mCurrentOrigin.x.toInt(),mCurrentOrigin.y.toInt(),(velocityX * mXScrollingSpeed).toInt(),0,Int.MIN_VALUE,Int.MAX_VALUE,0,0)Direction.VERTICAL -> {}}ViewCompat.postInvalidateOnAnimation(this@HomePageBPVIew)return true}//单击事件override fun onSingleTapConfirmed(e: MotionEvent): Boolean {return super.onSingleTapConfirmed(e)}//长按override fun onLongPress(e: MotionEvent) {super.onLongPress(e)}}override fun computeScroll() {superputeScroll()if (mScroller!!.isFinished) { //当前滚动是否结束if (mCurrentFlingDirection != Direction.NONE) {goToNearestBar()}} else {if (mCurrentFlingDirection != Direction.NONE && forceFinishScroll()) { //惯性滑动时保证最左边条目展示正确goToNearestBar()} else if (mScroller!!puteScrollOffset()) { //滑动是否结束 记录最新的滑动的点 惯性滑动处理mCurrentOrigin.y = mScroller!!.currY.toFloat()mCurrentOrigin.x = mScroller!!.currX.toFloat()ViewCompat.postInvalidateOnAnimation(this)}}}/*** Check if scrolling should be stopped.** @return true if scrolling should be stopped before reaching the end of animation.*/private fun forceFinishScroll(): Boolean {return mScroller!!.currVelocity <= mMinimumFlingVelocity}override fun onTouchEvent(event: MotionEvent): Boolean {//将view的OnTouchEvent事件交给手势监听器处理val `val` = mGestureDetector!!.onTouchEvent(event)// 正常滑动结束后 处理最左边的条目if (event.action == MotionEvent.ACTION_UP && mCurrentFlingDirection == Direction.NONE) {if (mCurrentScrollDirection == Direction.RIGHT || mCurrentScrollDirection == Direction.LEFT) {goToNearestBar()}mCurrentScrollDirection = Direction.NONE}return `val`}private fun goToNearestBar() {//让最左边的条目 显示出来var leftBar = mCurrentOrigin.x / (barWidth + interval).toDouble()leftBar = if (mCurrentFlingDirection != Direction.NONE) {// 跳到最近一个barMath.round(leftBar).toDouble()} else if (mCurrentScrollDirection == Direction.LEFT) {// 跳到上一个barMath.floor(leftBar)} else if (mCurrentScrollDirection == Direction.RIGHT) {// 跳到下一个barMath.ceil(leftBar)} else {// 跳到最近一个barMath.round(leftBar).toDouble()}val nearestOrigin = (mCurrentOrigin.x - leftBar * (barWidth + interval)).toInt()if (nearestOrigin != 0) {// 停止当前动画mScroller!!.forceFinished(true)//开始滚动mScroller!!.startScroll(mCurrentOrigin.x.toInt(),mCurrentOrigin.y.toInt(),-nearestOrigin,0,(Math.abs(nearestOrigin) / (barWidth + interval) * mScrollDuration).toInt())ViewCompat.postInvalidateOnAnimation(this@HomePageBPVIew)}//重新设置滚动方向.mCurrentFlingDirection = Direction.NONEmCurrentScrollDirection = mCurrentFlingDirection}constructor(context: Context) : this(context, null) {mContext = contextinit()}constructor(context: Context,attrs: AttributeSet?) : this(context, attrs, 0) {mContext = contextinit()}override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {super.onMeasure(widthMeasureSpec, heightMeasureSpec)//宽度的模式val mWidthModle = MeasureSpec.getMode(widthMeasureSpec)//宽度大小val mWidthSize = MeasureSpec.getSize(widthMeasureSpec)val mHeightModle = MeasureSpec.getMode(heightMeasureSpec)val mHeightSize = MeasureSpec.getSize(heightMeasureSpec)//如果明确大小,直接设置大小if (mWidthModle == MeasureSpec.EXACTLY) {mWidth = mWidthSize} else {//计算宽度,可以根据实际情况进行计算mWidth = paddingLeft + paddingRight//如果为AT_MOST, 不允许超过默认宽度的大小if (mWidthModle == MeasureSpec.AT_MOST) {mWidth = Math.min(mWidth, mWidthSize)}}if (mHeightModle == MeasureSpec.EXACTLY) {mHeight = mHeightSize} else {mHeight = getPaddingTop() + paddingBottomif (mHeightModle == MeasureSpec.AT_MOST) {mHeight = Math.min(mHeight, mHeightSize)}}//设置测量完成的宽高setMeasuredDimension(mWidth, mHeight)}override fun onLayout(changed: Boolean,left: Int,top: Int,right: Int,bottom: Int) {super.onLayout(changed, left, top, right, bottom)mWidth = widthmHeight = (getHeight() - paddingTop).toInt()chartWidth = mWidth - outSpacebarWidth = 100finterval = 30fstartChart = outSpace//横坐标textStart = startChart + barWidth / 2f}private fun init() {//初始化手势mGestureDetector = GestureDetectorCompat(mContext, mGestureListener)// 解决长按屏幕后无法拖动的现象 但是 长按 用不了mGestureDetector!!.setIsLongpressEnabled(false)mScroller = OverScroller(mContext, FastOutLinearInInterpolator())mMinimumFlingVelocity = ViewConfiguration.get(mContext).scaledMinimumFlingVelocitymBound = Rect()//线画笔linePaint = Paint()linePaint!!.isAntiAlias = truelinePaint!!.color = UIUtils.getColor(R.color.bp_chart_line_bg)//x纵坐标 画笔textXpaint = TextPaint()textXpaint!!.isAntiAlias = truetextXpaint!!.textSize = 27ftextXpaint!!.textAlign = Paint.Align.CENTER//Y纵坐标 画笔textYpaint = TextPaint()textYpaint!!.isAntiAlias = truetextYpaint!!.textSize = 28ftextYpaint!!.textAlign = Paint.Align.LEFTif (themeColor?.grayTextColor != null) {textYpaint!!.color = Color.parseColor(themeColor?.grayTextColor)}else {textYpaint!!.color = textColor}//Y轴背景yBackgroundPaint = Paint()yBackgroundPaint!!.color = UIUtils.getColor(R.color.bp_chart_line)//        //无数据时的画笔
//        noDataPaint = new Paint();
//        noDataPaint.setAntiAlias(true);
//        noDataPaint.setColor(noDataColor);
//        noDataPaint.setStyle(Paint.Style.FILL);}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)
//        canvas.drawColor(getColor(R.color.bt_grey_color))canvas.drawColor(bgColor)val lineInterval = (mHeight - bottomHeight) / 6f //横线之间的间距  纵向val textHeight = mHeight + paddingTop - bottomHeight //横坐标高度if (mCurrentOrigin.x < width - (ecgList.size * barWidth + (ecgList.size - 1) * interval + outSpace)) mCurrentOrigin.x =width - (ecgList.size * barWidth + (ecgList.size - 1) * interval + outSpace)if (mCurrentOrigin.x > 0) mCurrentOrigin.x = 0fdrawYtext(canvas, lineInterval, textHeight)val textTempStart = textStartdrawXtext(canvas, textTempStart)val chartTempStart = startChartvar size = (mHeight - bottomHeight) / 150f //比例drawBar(canvas, chartTempStart, size)}private fun drawBar(canvas: Canvas,chartTempStart: Float,size: Float) {var chartTempStart = chartTempStartcanvas.clipRect(outSpace - 10f, 0f, mWidth.toFloat(), getHeight().toFloat())//                canvas.clipRect(outSpace, getHeight() - bottomHeight, mWidth, getHeight());val mPaint = Paint()mPaint.color = UIUtils.getColor(R.color.bp_chart_point)mPaint.style = Paint.Style.FILLmPaint.strokeWidth = 30fval LinePaint = Paint()LinePaint.color = UIUtils.getColor(R.color.bp_chart_line)LinePaint.style = Paint.Style.FILLLinePaint.strokeWidth = 13ffor (i in ecgList.indices) {//每个数据点所占的Y轴高度val barHeight =ecgList[i].dbp / java.lang.Float.valueOf(maxValue) * 200f * size//            float realBarHeight = barHeight * mAnimator.getPhaseY();val left = chartTempStart + mCurrentOrigin.xval top = mHeight - bottomHeight + paddingTopval right = chartTempStart + barWidth + mCurrentOrigin.xval bottom = mHeight + paddingTop - bottomHeightval topLow = mHeight - ecgList[i].dbp * sizeval topHigeht = mHeight - ecgList[i].sbp * sizeval startX = (left + right) / 2canvas.drawLine(startX, topHigeht - 8f, startX, topLow + 8f, LinePaint)canvas.drawCircle(startX, topLow + 8f, 15f, mPaint) //坐标修改偏移量等于半径的议案canvas.drawCircle(startX, topHigeht - 8f, 15f, mPaint)chartTempStart += barWidth + interval}}override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {super.onSizeChanged(w, h, oldw, oldh)weight = 0.85f * wheight = 0.3f * h}private val timeFormat = SimpleDateFormat("HH:mm:ss")/*** 格式化时间 时间格式HH:mm:ss** @return*/fun formatTime(date: Date?): String {return timeFormat.format(date)}/*** 画x轴** @param canvas* @param textTempStart*/private fun drawXtext(canvas: Canvas,textTempStart: Float) {var textTempStart = textTempStartcanvas.clipRect(outSpace - 10f, 0f, mWidth.toFloat(), getHeight().toFloat())for (i in ecgList.indices) {canvas.drawText(formatTime(ecgList[i].date),textTempStart + mCurrentOrigin.x,//文字top值10fmHeight + paddingTop - 10f + mBound!!.height() / 2f,textXpaint!!)textTempStart += barWidth + interval}}private val y_title =arrayOf("", "", "", "", "")/*** 画Y轴** @param canvas* @param lineInterval* @param textHeight*/private fun drawYtext(canvas: Canvas,lineInterval: Float,textHeight: Float) {val min_height = textHeight / 4
//        canvas.drawLine(
//            42f,
//            52 + textHeight ,
//            mWidth.toFloat()-42,
//            52 + textHeight ,
//            textYpaint!!
//        )canvas.drawText(y_title[0], 0f, 32 + textHeight , textYpaint!!)// 虚线var mPaint :Paint = Paint(Paint.ANTI_ALIAS_FLAG)mPaint.color = resources.getColor(R.color.gray_date_text_color)mPaint.strokeWidth = 0.1fmPaint.pathEffect = DashPathEffect(floatArrayOf(3f, 3f), 0f)val centerY = height / 20val centerY2 = height//    setLayerType(LAYER_TYPE_SOFTWARE, null)canvas.drawLine(42f,52 + textHeight ,mWidth.toFloat()-42,52 + textHeight ,mPaint)//   canvas.drawLine(0f+60f, centerY.toFloat()-13f, width.toFloat()-55f, centerY.toFloat()-13f, mPaint)canvas.drawLine(0f+60f, centerY2.toFloat()-37f, width.toFloat()-55f, centerY2.toFloat()-37f, mPaint)//限制线
//        canvas.drawLine(
//            outSpace - 10f,
//            32 + min_height*2 ,
//            mWidth.toFloat(),
//            32 + min_height*2 ,
//            textYpaint!!
//        )
//        canvas.drawText(y_title[0], 0f, 32 + min_height*2 , textYpaint!!)
//        for (i in 1 downTo 0) {
//            canvas.drawLine(
//                outSpace - 10f,
//                32 + textHeight * i,
//                mWidth.toFloat(),
//                32 + textHeight * i,
//                textYpaint!!
//            )
//            canvas.drawText(y_title[0], 0f, 32 + min_height * i, textYpaint!!)
//        }}/*** 重新指定起始位置** @param verticalList*/private fun measureWidthShort(verticalList: List<Float>) {startChart = outSpacetextStart = startChart + barWidth / 2f}fun setBPData(verticalList: List<BPBean>) {//过滤最大值和最小值ecgList = verticalListinvalidate()}companion object {private const val TAG = "ScrollBar"}init {init()}}

BPBean.kt

package com.example.myapplicationimport io.realm.RealmObject
import io.realm.annotations.RealmClass
import java.util.*open  class BPBean(open var macAddress: String = "",open var sbp: Int=0,//高压open var dbp: Int=0,//低压open var isHistory: Boolean=false,open var date: Date? = null,open var year : Int=0,open var month: Int=0,open var week: Int=0,open var day: Int=0){override fun toString(): String {return "BPBean(macAddress='$macAddress', sbp=$sbp, dbp=$dbp, isHistory=$isHistory, date=$date, year=$year, month=$month, week=$week, day=$day)"}
}

更多推荐

自定义View血压

本文发布于:2024-02-14 06:36:01,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1762217.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   血压   View

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!