自定义View血压

使用
var bpList = mutableListOf()

av_specific_bp.setBPData(this.bpList)

     <com.oplayer.orunningplus.view.HomePageBPVIew
		android: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? = null
    private var textStart = 0f
    private var mHeight = 0
    private var mWidth = 0
    private var ecgList: List<BPBean> = ArrayList()
    private val verticalWidth = 100f
    private var chartWidth=0f //表的总宽度,除过外间距 = 0f
    private val outSpace = verticalWidth // 柱子与纵轴的距离
    private var startChart = verticalWidth //柱子开始的横坐标
    private var interval=0f //柱子之间的间隔 = 0f
    private var barWidth=0f //柱子的宽度 = 0f
    private val bottomHeight = 100f //底部横坐标高度
    private val maxValue = "230" //默认最大值
    private val middleValue = "1"
    private val paddingTop = 20f
    private val noDataPaint: Paint? = null
    private var textXpaint: TextPaint? = null
    private var linePaint: Paint? = null

    private val textColor = UIUtils.getColor(R.color.gray_date_text_color)
    private val bgColor = ContextCompat.getColor(mContext,R.color.colorPrimary)
    private val mDuriation = 3000
    private var textYpaint: TextPaint? = null

    //    private ChartAnimator mAnimator;
    private var mGestureDetector: GestureDetectorCompat? = null
    private var mScroller: OverScroller? = null
    private var yBackgroundPaint: Paint? = null
    private var weight = 0f
    private var height = 0f

    enum class Direction {
        NONE, LEFT, RIGHT, VERTICAL
    }

    //正常滑动方向
    private var mCurrentScrollDirection = Direction.NONE

    //快速滑动方向
    private var mCurrentFlingDirection = Direction.NONE
    private val mHorizontalFlingEnabled = true
    private val mCurrentOrigin = PointF(0f, 0f)
    private val mScrollDuration = 250

    //滑动速度
    private val mXScrollingSpeed = 1f
    private 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 * mXScrollingSpeed
                    ViewCompat.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 = mCurrentScrollDirection
            mScroller!!.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() {
        super.computeScroll()
        if (mScroller!!.isFinished) { //当前滚动是否结束
            if (mCurrentFlingDirection != Direction.NONE) {
                goToNearestBar()
            }
        } else {
            if (mCurrentFlingDirection != Direction.NONE && forceFinishScroll()) { //惯性滑动时保证最左边条目展示正确
                goToNearestBar()
            } else if (mScroller!!.computeScrollOffset()) { //滑动是否结束 记录最新的滑动的点 惯性滑动处理
                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) {
            // 跳到最近一个bar
            Math.round(leftBar).toDouble()
        } else if (mCurrentScrollDirection == Direction.LEFT) {
            // 跳到上一个bar
            Math.floor(leftBar)
        } else if (mCurrentScrollDirection == Direction.RIGHT) {
            // 跳到下一个bar
            Math.ceil(leftBar)
        } else {
            // 跳到最近一个bar
            Math.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.NONE
        mCurrentScrollDirection = mCurrentFlingDirection
    }

    constructor(context: Context) : this(context, null) {
        mContext = context
        init()
    }

    constructor(
        context: Context,
        attrs: AttributeSet?
    ) : this(context, attrs, 0) {
        mContext = context
        init()
    }

    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() + paddingBottom
            if (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 = width
        mHeight = (getHeight() - paddingTop).toInt()
        chartWidth = mWidth - outSpace
        barWidth = 100f
        interval = 30f
        startChart = outSpace


        //横坐标
        textStart = startChart + barWidth / 2f
    }

    private fun init() {

        //初始化手势
        mGestureDetector = GestureDetectorCompat(mContext, mGestureListener)

        // 解决长按屏幕后无法拖动的现象 但是 长按 用不了
        mGestureDetector!!.setIsLongpressEnabled(false)
        mScroller = OverScroller(mContext, FastOutLinearInInterpolator())
        mMinimumFlingVelocity = ViewConfiguration.get(mContext).scaledMinimumFlingVelocity
        mBound = Rect()


        //线画笔
        linePaint = Paint()
        linePaint!!.isAntiAlias = true
        linePaint!!.color = UIUtils.getColor(R.color.bp_chart_line_bg)

        //x纵坐标 画笔
        textXpaint = TextPaint()
        textXpaint!!.isAntiAlias = true
        textXpaint!!.textSize = 27f
        textXpaint!!.textAlign = Paint.Align.CENTER


        //Y纵坐标 画笔
        textYpaint = TextPaint()
        textYpaint!!.isAntiAlias = true
        textYpaint!!.textSize = 28f
        textYpaint!!.textAlign = Paint.Align.LEFT
        if (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 = 0f
        drawYtext(canvas, lineInterval, textHeight)
        val textTempStart = textStart
        drawXtext(canvas, textTempStart)
        val chartTempStart = startChart
        var size = (mHeight - bottomHeight) / 150f //比例

        drawBar(canvas, chartTempStart, size)
    }

    private fun drawBar(
        canvas: Canvas,
        chartTempStart: Float,
        size: Float
    ) {
        var chartTempStart = chartTempStart
        canvas.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.FILL
        mPaint.strokeWidth = 30f
        val LinePaint = Paint()
        LinePaint.color = UIUtils.getColor(R.color.bp_chart_line)
        LinePaint.style = Paint.Style.FILL
        LinePaint.strokeWidth = 13f
        for (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.x
            val top = mHeight - bottomHeight + paddingTop
            val right = chartTempStart + barWidth + mCurrentOrigin.x
            val bottom = mHeight + paddingTop - bottomHeight
            val topLow = mHeight - ecgList[i].dbp * size
            val topHigeht = mHeight - ecgList[i].sbp * size
            val startX = (left + right) / 2
            canvas.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 * w
        height = 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 = textTempStart
        canvas.clipRect(outSpace - 10f, 0f, mWidth.toFloat(), getHeight().toFloat())
        for (i in ecgList.indices) {
            canvas.drawText(
                formatTime(
                    ecgList[i].date
                ),
                textTempStart + mCurrentOrigin.x,
                //文字top值10f
                mHeight + 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.1f
        mPaint.pathEffect = DashPathEffect(floatArrayOf(3f, 3f), 0f)
        val centerY = height / 20
        val 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 = outSpace
        textStart = startChart + barWidth / 2f
    }

    fun setBPData(verticalList: List<BPBean>) {
        //过滤最大值和最小值
        ecgList = verticalList
        invalidate()
    }

    companion object {
        private const val TAG = "ScrollBar"
    }

    init {
        init()
    }

}

BPBean.kt

package com.example.myapplication

import 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)"
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信工院李平

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值