Android运动健康血氧自定义控件

news/2024/11/22 4:00:06/
kotlin">/**** 日图表* zrj 2020/9/1*/
class BODayChart(context: Context, attrs: AttributeSet?) : View(context, attrs) {//屏幕宽高private var scrWidth = 0fprivate var scrHeight = 0fprivate var xData: Array<String> = arrayOf("00:00", "06:00", "12:00", "18:00", "00:00")private var yData: Array<Int> = arrayOf(100, 90, 85, 80, 70)private var boData = mutableListOf<Int>()private lateinit var paintLine: Paintprivate lateinit var paintGradientLine: Paintprivate lateinit var paintXText: Paintprivate lateinit var paintYText: Paintprivate lateinit var paintPillar: Paintprivate lateinit var paintRound: Paintprivate lateinit var paintBessel: Paintprivate var animDuration = 500Lprivate var anim: ValueAnimator? = nullprivate var mPercent = 0f //动画进度private var xSlider = 0f //滑块的x轴位置private var mPath: Pathprivate val curveCircleRadius = 12f.dp// the coordinates of the first curveprivate val mFirstCurveStartPoint = Point()private val mFirstCurveEndPoint = Point()private val mFirstCurveControlPoint1 = Point()private val mFirstCurveControlPoint2 = Point()//the coordinates of the second curveprivate var mSecondCurveStartPoint = Point()private val mSecondCurveEndPoint = Point()private val mSecondCurveControlPoint1 = Point()private val mSecondCurveControlPoint2 = Point()init {setLayerType(LAYER_TYPE_SOFTWARE, null)mPath = Path()initPaint()}/*** 初始化画笔*/private fun initPaint() {paintLine = Paint()paintLine.style = Paint.Style.STROKEpaintLine.strokeWidth = 1fpaintLine.color = context.colorCompat(R.color.e6e6e6_2e2e2e)paintGradientLine = Paint()paintGradientLine.style = Paint.Style.STROKEpaintGradientLine.strokeWidth = 2fpaintXText = Paint()paintXText.isAntiAlias = truepaintXText.strokeWidth = 1fpaintXText.textSize = 12f.sppaintXText.textAlign = Paint.Align.CENTERpaintXText.color = context.colorCompat(R.color.color_on_surface)paintYText = Paint()paintYText.isAntiAlias = truepaintYText.textSize = 12f.sppaintYText.strokeWidth = 1fpaintYText.textAlign = Paint.Align.RIGHTpaintYText.color = context.colorCompat(R.color.secondary_666666_808080)paintPillar = Paint()paintPillar.style = Paint.Style.FILLpaintPillar.isAntiAlias = truepaintPillar.color = context.colorCompat(R.color.fc355c_fc3159)paintRound = Paint()paintRound.style = Paint.Style.FILLpaintRound.isAntiAlias = truepaintRound.color = context.colorCompat(R.color.ffffff_6e6e6e)paintBessel = Paint()paintBessel.style = Paint.Style.FILLpaintBessel.isAntiAlias = truepaintBessel.color = context.colorCompat(R.color.f2f2f2_1d1d1d)}override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {parent.requestDisallowInterceptTouchEvent(true)return super.dispatchTouchEvent(ev)}override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {super.onSizeChanged(w, h, oldw, oldh)scrWidth = width.toFloat()scrHeight = height.toFloat()ySpacing = scrHeight / 10f //y轴分10份//底部圆滑块可以滑动的范围xWithStart = margin + paintXText.measureText(xData[0]) / 2xWithEnd = scrWidth - margin - paintYText.measureText(yData[0].toString()) * 2.5fxTextSpacing = (xWithEnd - xWithStart) / (xData.size - 1)xSpacing = xTextSpacing / 36 //x轴等分4份   144}private var mDownX = 0fprivate var mDownY = 0fprivate var isSlider = false@SuppressLint("ClickableViewAccessibility")override fun onTouchEvent(event: MotionEvent): Boolean {when (event.action) {MotionEvent.ACTION_DOWN -> {mDownX = event.xmDownY = event.yisSlider = abs(event.x - xSlider) < 60f && abs(event.y - ySpacing * 9) < 60f}MotionEvent.ACTION_MOVE ->if (abs(event.y - mDownY) < abs(event.x - mDownX)) {if (isSlider) {xSlider = event.xinvalidate()}}MotionEvent.ACTION_UP -> {if (isSlider) {if (xSlider < xWithStart) {xSlider = xWithStartinvalidate()}if (xSlider > xWithEnd) {xSlider = xWithEndinvalidate()}boData.forEachIndexed { index, _ ->val x = xWithStart + xSpacing * indexval dis = abs(x - xSlider)if (dis < xSpacing / 2) {xSlider = xinvalidate()return@forEachIndexed}}} else {if (abs(event.x - mDownX) > xSpacing) {onDayMoveListener?.invoke(event.x > mDownX)} else {boData.forEachIndexed { index, _ ->val x = xWithStart + xSpacing * indexval dis = abs(x - event.x)if (dis < xSpacing) {xSlider = xinvalidate()return@forEachIndexed}}}}}}return true}private val margin = 20f.dp //左右两边距离private var xWithStart = 0f //x轴的起始点private var xWithEnd = 0f  //x轴结束点private var ySpacing = 0f //高度分割份数后间距private var xSpacing = 0f //x轴柱子分割份数后间距private var xTextSpacing = 0f //x轴文字分割份数后间距@SuppressLint("DrawAllocation")override fun onDraw(canvas: Canvas) {super.onDraw(canvas)//画y轴方向横线与文字drawY(canvas)//垂直渐变线drawGradientLine(canvas)//画柱子drawPillar(canvas)//底部drawBessel(canvas)//画x轴方向文字drawX(canvas)}private fun drawX(canvas: Canvas) {xData.forEachIndexed { index, s ->val x = xWithStart + xTextSpacing * indexval dis = abs(x - xSlider)var y = ySpacing * 9 - 10fif (dis < xTextSpacing / 2) {paintXText.typeface = Typeface.DEFAULT_BOLDy -= 40f * (1 - dis / xTextSpacing)} else {paintXText.typeface = Typeface.DEFAULT}canvas.drawText(s, x, y, paintXText)}}private fun drawPillar(canvas: Canvas) {boData.forEachIndexed { index, i ->if (xSlider < xWithStart + xSpacing * index + xSpacing / 2 && xSlider > xWithStart + xSpacing * index - xSpacing / 2) {onDaySelectListener?.invoke(index, i)}if (i > 89) {paintPillar.color = Color.parseColor("#00d656")} else {paintPillar.color = Color.parseColor("#fdc221")}if (i > 0) {canvas.drawRoundRect(RectF(xWithStart + xSpacing * index - xSpacing / 2,ySpacing + ySpacing * ((100 - i) / 5f) * mPercent,xWithStart + xSpacing * index + xSpacing / 2,ySpacing * 7), 2f, 2f, paintPillar)}}}private fun drawY(canvas: Canvas) {var k = 1for (i in 0..4) {if (i > 0) {k = i + 2}if (i == 4) {k = 7}canvas.drawLine(margin,ySpacing * k,scrWidth - margin,ySpacing * k,paintLine)canvas.drawText("${yData[i]}%",scrWidth - margin,ySpacing * k - 10f,paintYText)}}private fun drawBessel(canvas: Canvas) {// 第一条曲线开始点mFirstCurveStartPoint[(xSlider - curveCircleRadius * 3).toInt()] = (ySpacing * 9).toInt()// 第一条曲线结束点mFirstCurveEndPoint[xSlider.toInt()] =(ySpacing * 9 - curveCircleRadius - curveCircleRadius / 4).toInt()// 第二条开始点mSecondCurveStartPoint = mFirstCurveEndPointmSecondCurveEndPoint[(xSlider + curveCircleRadius * 3).toInt()] = (ySpacing * 9).toInt()// 第一条控制点mFirstCurveControlPoint1[(mFirstCurveStartPoint.x + curveCircleRadius + curveCircleRadius / 4).toInt()] =mFirstCurveStartPoint.ymFirstCurveControlPoint2[(mFirstCurveEndPoint.x - curveCircleRadius * 2 + curveCircleRadius).toInt()] =mFirstCurveEndPoint.y// 第二条控制点mSecondCurveControlPoint1[(mSecondCurveStartPoint.x + curveCircleRadius * 2 - curveCircleRadius).toInt()] =mSecondCurveStartPoint.ymSecondCurveControlPoint2[(mSecondCurveEndPoint.x - curveCircleRadius - curveCircleRadius / 4).toInt()] =mSecondCurveEndPoint.ymPath.reset()mPath.moveTo(0f, ySpacing * 9)mPath.lineTo(mFirstCurveStartPoint.x.toFloat(), mFirstCurveStartPoint.y.toFloat())mPath.cubicTo(mFirstCurveControlPoint1.x.toFloat(), mFirstCurveControlPoint1.y.toFloat(),mFirstCurveControlPoint2.x.toFloat(), mFirstCurveControlPoint2.y.toFloat(),mFirstCurveEndPoint.x.toFloat(), mFirstCurveEndPoint.y.toFloat())mPath.cubicTo(mSecondCurveControlPoint1.x.toFloat(), mSecondCurveControlPoint1.y.toFloat(),mSecondCurveControlPoint2.x.toFloat(), mSecondCurveControlPoint2.y.toFloat(),mSecondCurveEndPoint.x.toFloat(), mSecondCurveEndPoint.y.toFloat())mPath.lineTo(scrWidth, ySpacing * 9)mPath.lineTo(scrWidth, scrHeight)mPath.lineTo(0f, scrHeight)mPath.close()//底部灰色canvas.drawPath(mPath, paintBessel)//底部滑块canvas.drawCircle(xSlider, ySpacing * 9 + 5f, curveCircleRadius, paintRound)}fun setValue(value: MutableList<Int>, time: Int): BODayChart {boData.clear()boData.addAll(value)xSlider = xSpacing * time + xWithStartstartAnimation()return this}private fun startAnimation() {anim = ValueAnimator.ofObject(AngleEvaluator(), 0f, 1f)anim?.interpolator = AccelerateDecelerateInterpolator()anim?.addUpdateListener { animation ->mPercent = animation.animatedValue as FloatpostInvalidate()}anim?.duration = animDurationanim?.start()}private fun drawGradientLine(canvas: Canvas) {val mLinearGradient = LinearGradient(xSlider, ySpacing, xSlider, ySpacing * 8,intArrayOf(context.colorCompat(R.color.ffffff_262626),context.colorCompat(R.color.fc355c_fc3159),context.colorCompat(R.color.ffffff_262626)), null, Shader.TileMode.MIRROR)paintGradientLine.shader = mLinearGradientif (ySpacing > 0) {canvas.drawLine(xSlider, ySpacing, xSlider, ySpacing * 8, paintGradientLine)}}private var onDaySelectListener: ((index: Int, value: Int) -> Unit)? = nullfun setOnDaySelectListener(l: ((index: Int, value: Int) -> Unit)): BODayChart {this.onDaySelectListener = lreturn this}private var onDayMoveListener: ((isPre: Boolean) -> Unit)? = nullfun setOnDayMoveListener(l: ((index: Boolean) -> Unit)): BODayChart {this.onDayMoveListener = lreturn this}
}

转自https://juejin.cn/post/6944670773520891912?from=search-suggest


http://www.ppmy.cn/news/1548633.html

相关文章

RabbitMQ消息可靠性保证机制4--消费端限流

7.7 消费端限流 在类似如秒杀活动中&#xff0c;一开始会有大量并发写请求到达服务端&#xff0c;城机对消息进行削峰处理&#xff0c;如何做&#xff1f; 当消息投递的速度远快于消费的速度时&#xff0c;随着时间积累就会出现“消息积压”。消息中间件本身是具备一定的缓冲…

如何解决网站被渗透:全面指南与实践

网站被渗透&#xff08;即遭受黑客攻击&#xff09;是一个严重的问题&#xff0c;可能导致数据泄露、服务中断以及经济损失。面对这种情况&#xff0c;及时有效的应对措施至关重要。本文将详细介绍从检测到恢复的一系列步骤&#xff0c;帮助网站管理员迅速解决问题&#xff0c;…

集群聊天服务器(13)redis环境安装和发布订阅命令

目录 环境安装订阅redis发布-订阅的客户端编程环境配置客户端编程 功能测试 环境安装 sudo apt-get install redis-server 先启动redis服务 /etc/init.d/redis-server start默认在6379端口上 redis是存键值对的&#xff0c;还可以存链表、数组等等复杂数据结构 而且数据是在…

javaweb学习——Day2

JS对象 1、array 定义&#xff1a; var namenew Array(元素列表); var name[元素列表] 访问&#xff1a; name[索引]值 array的属性和方法 length属性&#xff0c;获取数组长度 foreach():遍历数组元素 x.forEach(element > { console.log(element); }); push():…

【Unity基础】对比Unity中两种粒子系统

在Unity中&#xff0c;Particle System和Visual Effect Graph (VFX) 都是用于创建粒子效果的工具&#xff0c;但它们的设计目标、使用场景和功能特点有所不同。以下是详细对比&#xff1a; 1. Particle System 特点 传统粒子系统&#xff0c;Unity自带的模块化粒子特效工具。…

stm32学习笔记----51单片机和stm32单片机的区别

51单片机和32单片机的区别可以从多个方面进行比较&#xff0c;主要包括架构、处理能力、指令集、外设支持和应用领域等。以下是两者的详细对比&#xff1a; 1. 架构 51单片机&#xff1a;基于8位微处理器架构&#xff0c;最初由Intel开发&#xff0c;并且现在主要由Atmel、NXP…

【ArcGIS微课1000例】0127:计算城市之间的距离

本文讲述,在ArcGIS中,计算城市(以地级城市为例)之间的距离,效果如下图所示: 一、数据准备 加载配套实验数据包中的地级市和行政区划矢量数据(订阅专栏后,从私信查收数据),如下图所示: 二、计算距离 1. 计算邻近表 ArcGIS提供了计算点和另外点之间距离的工具:分析…

Ubuntu22.04.2 k8s部署

k8s介绍 简单介绍 通俗易懂的解释&#xff1a; Kubernetes&#xff08;也被称为 K8s&#xff09;就像是一个大管家&#xff0c;帮你管理你的云计算服务。想象一下&#xff0c;你有很多个小程序&#xff08;我们称之为“容器”&#xff09;&#xff0c;每个都在做不同的事情&…