日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Android運動健康睡眠自定義控件的實現

瀏覽:20日期:2022-09-20 08:56:39
效果圖

Android運動健康睡眠自定義控件的實現

代碼

/** * * 日圖表 * zrj 2020/8/25 */class SleepDayChart(context: Context, attrs: AttributeSet?) : View(context, attrs) { //屏幕寬高 private var scrWidth = 0f private var scrHeight = 0f private var xData: Array<String> = arrayOf('20:00', '02:00', '08:00', '14:00', '20:00') private var sleepsData: Sleep? = null private lateinit var paintLine: Paint private lateinit var paintGradientLine: Paint private lateinit var paintXText: Paint private lateinit var paintSleep: Paint private lateinit var paintPillar: Paint private lateinit var paintRound: Paint private lateinit var paintBessel: Paint private var xSlider = 0f //滑塊的x軸位置 private var mPath: Path private val curveCircleRadius = 12f.dp // the coordinates of the first curve private val mFirstCurveStartPoint = Point() private val mFirstCurveEndPoint = Point() private val mFirstCurveControlPoint1 = Point() private val mFirstCurveControlPoint2 = Point() //the coordinates of the second curve private 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.STROKE paintLine.strokeWidth = 1f paintLine.color = context.colorCompat(R.color.e6e6e6_2e2e2e) paintGradientLine = Paint() paintGradientLine.style = Paint.Style.STROKE paintGradientLine.strokeWidth = 1f paintXText = Paint() paintXText.isAntiAlias = true paintXText.strokeWidth = 1f paintXText.textSize = 12f.sp paintXText.textAlign = Paint.Align.CENTER paintXText.color = context.colorCompat(R.color.color_on_surface) paintSleep = Paint() paintSleep.style = Paint.Style.FILL paintSleep.isAntiAlias = true paintSleep.color = context.colorCompat(R.color.blue_7fbeff) paintPillar = Paint() paintPillar.style = Paint.Style.FILL paintPillar.isAntiAlias = true paintPillar.color = context.colorCompat(R.color.blue_7fbeff) paintRound = Paint() paintRound.style = Paint.Style.FILL paintRound.isAntiAlias = true paintRound.color = context.colorCompat(R.color.ffffff_6e6e6e) paintBessel = Paint() paintBessel.style = Paint.Style.FILL paintBessel.isAntiAlias = true paintBessel.color = context.colorCompat(R.color.f2f2f2_1d1d1d) } 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 / 8f //y軸分8份 //底部圓滑塊可以滑動的范圍 xWithStart = margin * 3 xWithEnd = scrWidth - margin * 3 xSlider = scrWidth / 2 xSpacing = (xWithEnd - xWithStart) / (xData.size - 1) } override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { parent.requestDisallowInterceptTouchEvent(true) return super.dispatchTouchEvent(ev) } private var mDownX = 0f private var mDownY = 0f private 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 * 7) < 60freturn isSlider } MotionEvent.ACTION_MOVE ->if (abs(event.y - mDownY) < abs(event.x - mDownX)) { if (isSlider) { xSlider = event.x if (xSlider < xWithStart) { xSlider = xWithStart } if (xSlider > xWithEnd) { xSlider = xWithEnd } invalidate() }} MotionEvent.ACTION_UP -> {if (!isSlider) { if (abs(event.x - mDownX) < curveCircleRadius) { xSlider = event.x invalidate() }} } } 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軸分割份數后間距 @SuppressLint('DrawAllocation') override fun onDraw(canvas: Canvas) { super.onDraw(canvas) //畫柱子 drawPillar(canvas) //垂直漸變線 drawGradientLine(canvas) //底部 drawBessel(canvas) //畫x軸方向文字 drawX(canvas) } private fun drawX(canvas: Canvas) { if (sleepsData == null) { xData.forEachIndexed { index, s ->val x = xWithStart + xSpacing * indexval dis = abs(x - xSlider)var y = ySpacing * 7 - 10f.dpif (dis < xSpacing / 2) { paintXText.typeface = Typeface.DEFAULT_BOLD y -= 10f.dp * (1 - dis / xSpacing)} else { paintXText.typeface = Typeface.DEFAULT}canvas.drawText(s, x, y, paintXText)if (index == 0) { canvas.drawText(startDay, x, y - 12f.dp, paintXText)}if (index == xData.size - 1) { canvas.drawText(endDay, x, y - 12f.dp, paintXText)} } } else { sleepsData?.let {val start = DateTime(it.items[0].timeStamp * 1000)val asleep = start.hourOfDay * 60 + start.minuteOfHourval end = DateTime(it.items.last().timeStamp * 1000)val wakeUp = end.hourOfDay * 60 + end.minuteOfHour + it.items.last().durationval s1 = '${context.getString(R.string.bed_time)} ${asleep / 60}:${if (asleep % 60 < 10) '0' else ''}${asleep % 60}'val dis1 = abs(xWithStart + paintXText.measureText(s1) / 2 - xSlider)var y1 = ySpacing * 7 - 10fif (dis1 < curveCircleRadius * 3) { paintXText.typeface = Typeface.DEFAULT_BOLD var temp = 1 - dis1 / curveCircleRadius * 2 if (temp < 0f || temp > 1f) { temp = 1f } y1 -= 60f * temp} else { paintXText.typeface = Typeface.DEFAULT}canvas.drawText(s1, xWithStart, y1, paintXText)canvas.drawText(startDay, xWithStart, y1 - 40f, paintXText)val hour = '${if (wakeUp / 60 < 10) '0' else ''}${wakeUp / 60}'val minute = '${if (wakeUp % 60 < 10) '0' else ''}${wakeUp % 60}'val s2 = '${context.getString(R.string.rise_time)} $hour:$minute'val dis2 = abs(xWithEnd - paintXText.measureText(s2) / 2 - xSlider)var y2 = ySpacing * 7 - 10fif (dis2 < curveCircleRadius * 3) { paintXText.typeface = Typeface.DEFAULT_BOLD y2 -= 60f * (1 - dis2 / (xSlider - curveCircleRadius * 3))} else { paintXText.typeface = Typeface.DEFAULT}canvas.drawText(s2, xWithEnd, y2, paintXText)canvas.drawText(endDay, xWithEnd, y2 - 40f, paintXText) } } } private fun drawPillar(canvas: Canvas) { var top = 0f var bottom = 0f var preDuration = 0 //前一狀態時長 var duration = 0 //時間累加 var tempTop = 0f var tempBottom: Float var startColor = 0 var endColor = 0 val colors = intArrayOf(startColor, endColor) sleepsData?.let { it.items.forEachIndexed { index, item ->when (item.status) { 3, 4 -> { //清醒 endColor = Color.parseColor('#fdc221') paintSleep.color = Color.parseColor('#fdc221') paintPillar.color = Color.parseColor('#f9eec1') top = 1f bottom = 2f } 12 -> { //快速眼動 endColor = Color.parseColor('#fd817c') paintSleep.color = Color.parseColor('#fd817c') paintPillar.color = Color.parseColor('#4dfd817c') top = 2f bottom = 3f } 0, 1 -> { //淺 endColor = Color.parseColor('#c64be4') paintSleep.color = Color.parseColor('#c64be4') paintPillar.color = Color.parseColor('#e8c3f1') top = 3f bottom = 4f } 2 -> { //深 endColor = Color.parseColor('#8a2be2') paintSleep.color = Color.parseColor('#8a2be2') paintPillar.color = Color.parseColor('#d6b9f1') top = 4f bottom = 5f }}if (xSlider < xWithStart + xSpacing * (duration + item.duration) && xSlider > xWithStart + xSpacing * duration) { onDaySelectListener?.invoke(index, item) canvas.drawRect( RectF( xWithStart + xSpacing * duration, ySpacing * top + 10f, xWithStart + xSpacing * (duration + item.duration), ySpacing * 7 ), paintPillar )}canvas.drawRoundRect( RectF( xWithStart + xSpacing * duration - 1f, ySpacing * top, xWithStart + xSpacing * (duration + item.duration) + 1f, ySpacing * bottom ), 10f, 10f, paintSleep)if (index > 0 && index < it.items.size) { if (tempTop < top) { tempTop += 0.9f tempBottom = bottom - 0.9f colors[0] = startColor colors[1] = endColor if (xSpacing * preDuration > 10f) { val path1 = Path() path1.moveTo(xWithStart + xSpacing * duration, ySpacing * tempTop) path1.lineTo(xWithStart + xSpacing * duration - 8f,ySpacing * tempTop + 6f ) path1.lineTo(xWithStart + xSpacing * duration, ySpacing * tempTop + 12f) path1.close() paintSleep.color = startColor canvas.drawPath(path1, paintSleep) } if (xSpacing * item.duration > 10f) { val path2 = Path() path2.moveTo(xWithStart + xSpacing * duration, ySpacing * tempBottom) path2.lineTo(xWithStart + xSpacing * duration + 8f,ySpacing * tempBottom - 6f ) path2.lineTo(xWithStart + xSpacing * duration,ySpacing * tempBottom - 12f ) path2.close() paintSleep.color = endColor canvas.drawPath(path2, paintSleep) } } else { tempBottom = tempTop + 0.1f tempTop = bottom - 0.1f colors[0] = endColor colors[1] = startColor if (xSpacing * preDuration > 10f) { val path1 = Path() path1.moveTo(xWithStart + xSpacing * duration, ySpacing * tempBottom) path1.lineTo(xWithStart + xSpacing * duration - 8f,ySpacing * tempBottom - 6f ) path1.lineTo(xWithStart + xSpacing * duration,ySpacing * tempBottom - 12f ) path1.close() paintSleep.color = startColor canvas.drawPath(path1, paintSleep) } if (xSpacing * item.duration > 10f) { val path2 = Path() path2.moveTo(xWithStart + xSpacing * duration, ySpacing * tempTop) path2.lineTo(xWithStart + xSpacing * duration + 8f,ySpacing * tempTop + 6f ) path2.lineTo(xWithStart + xSpacing * duration, ySpacing * tempTop + 12f) path2.close() paintSleep.color = endColor canvas.drawPath(path2, paintSleep) } } val mLinearGradient = LinearGradient( xWithStart + xSpacing * duration, ySpacing * tempTop, xWithStart + xSpacing * duration, ySpacing * tempBottom, colors, null, Shader.TileMode.MIRROR ) paintGradientLine.shader = mLinearGradient canvas.drawLine( xWithStart + xSpacing * duration, ySpacing * tempTop, xWithStart + xSpacing * duration, ySpacing * tempBottom, paintGradientLine )}tempTop = toptempBottom = bottompreDuration = item.durationduration += item.durationstartColor = endColor } } } private fun drawBessel(canvas: Canvas) { // 第一條曲線開始點 mFirstCurveStartPoint[(xSlider - curveCircleRadius * 3).toInt()] = (ySpacing * 7).toInt() // 第一條曲線結束點 mFirstCurveEndPoint[xSlider.toInt()] = (ySpacing * 7 - curveCircleRadius - curveCircleRadius / 4).toInt() // 第二條開始點 mSecondCurveStartPoint = mFirstCurveEndPoint mSecondCurveEndPoint[(xSlider + curveCircleRadius * 3).toInt()] = (ySpacing * 7).toInt() // 第一條控制點 mFirstCurveControlPoint1[(mFirstCurveStartPoint.x + curveCircleRadius + curveCircleRadius / 4).toInt()] = mFirstCurveStartPoint.y mFirstCurveControlPoint2[(mFirstCurveEndPoint.x - curveCircleRadius * 2 + curveCircleRadius).toInt()] = mFirstCurveEndPoint.y // 第二條控制點 mSecondCurveControlPoint1[(mSecondCurveStartPoint.x + curveCircleRadius * 2 - curveCircleRadius).toInt()] = mSecondCurveStartPoint.y mSecondCurveControlPoint2[(mSecondCurveEndPoint.x - curveCircleRadius - curveCircleRadius / 4).toInt()] = mSecondCurveEndPoint.y mPath.reset() mPath.moveTo(0f, ySpacing * 7) 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 * 7) mPath.lineTo(scrWidth, scrHeight) mPath.lineTo(0f, scrHeight) mPath.close() //底部灰色 canvas.drawPath(mPath, paintBessel) //底部滑塊 canvas.drawCircle(xSlider, ySpacing * 7 + 5f, curveCircleRadius, paintRound) } private var startDay = '' private var endDay = '' fun setValue(value: Sleep?, startDay: String, endDay: String): SleepDayChart { this.startDay = startDay this.endDay = endDay this.sleepsData = value if (sleepsData == null) { xSpacing = (xWithEnd - xWithStart) / (xData.size - 1) } else { sleepsData?.let {xSpacing = (xWithEnd - xWithStart) / it.total //時間段分割成分鐘 } } postInvalidate() return this } private fun drawGradientLine(canvas: Canvas) { if (sleepsData == null) { canvas.drawText(context.getString(R.string.no_sleep_data),scrWidth / 2f,scrHeight / 2f,paintXText ) } else { val mLinearGradient = LinearGradient(xSlider, ySpacing, xSlider, ySpacing * 6,intArrayOf( context.colorCompat(R.color.ffffff_262626), Color.parseColor('#0e83ff'), context.colorCompat(R.color.ffffff_262626)), null, Shader.TileMode.MIRROR ) paintGradientLine.shader = mLinearGradient if (ySpacing > 0) {canvas.drawLine(xSlider, ySpacing, xSlider, ySpacing * 6, paintGradientLine) } } } private var onDaySelectListener: ((index: Int, item: SleepItem) -> Unit)? = null fun setOnDaySelectListener(l: ((index: Int, item: SleepItem) -> Unit)): SleepDayChart { this.onDaySelectListener = l return this }}

以上就是Android實現運動健康睡眠自定義控件的詳細內容,更多關于Android 實現自定義控件的資料請關注好吧啦網其它相關文章!

標簽: Android
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
首页国产精品| 久久久久久亚洲精品美女| 国产精品成人a在线观看| 美女在线视频一区| 麻豆精品在线视频| 国产精品一区二区三区av | 日韩午夜高潮| 日韩国产激情| 国产亚洲福利| 国产专区一区| 亚洲自拍另类| 日本亚洲最大的色成网站www | 激情综合网站| 久久中文字幕av| 宅男噜噜噜66国产日韩在线观看| 日韩视频1区| 深夜福利一区| 国产一级成人av| 久久永久免费| 欧美一区久久久| 欧美亚洲国产一区| 视频一区视频二区中文字幕| 日韩精品亚洲专区| 国产另类在线| 精品视频一区二区三区在线观看| 99国产精品久久久久久久成人热| 欧美亚洲一级| 日本色综合中文字幕| 久久久91麻豆精品国产一区| 日韩理论视频| 亚洲精品一区二区在线看| 亚洲欧洲日本mm| 日韩成人在线看| 国产一区二区三区探花| 国产精品99免费看| 日韩精品中文字幕吗一区二区| 在线 亚洲欧美在线综合一区| 美女视频网站久久| caoporn视频在线| 99综合视频| 国产亚洲第一伦理第一区| 日韩av二区| 蜜桃免费网站一区二区三区| 国产欧美日韩综合一区在线播放| 国产国产精品| 亚洲一区二区三区高清不卡| 亚洲精品三级| 正在播放日韩精品| 免费看日韩精品| 卡一卡二国产精品| 99国产精品久久久久久久成人热| 亚洲先锋成人| 日韩在线成人| 成人福利视频| 亚洲aa在线| 日韩精品诱惑一区?区三区| 好看不卡的中文字幕| 欧美日本二区| 欧美二区视频| 国产精品尤物| 伊人影院久久| 国产成人精品一区二区免费看京| 国产精品一区二区中文字幕| 蜜桃成人精品| 综合一区在线| 中文字幕在线视频久| 亚洲综合小说| 在线一区视频观看| 国产欧美自拍| 亚洲一区国产| 日本不良网站在线观看| 91午夜精品| 欧美日韩国产亚洲一区| 精品久久久亚洲| 亚洲一区二区三区四区电影| 激情不卡一区二区三区视频在线| 免费观看亚洲天堂| 视频一区二区三区在线| 樱桃视频成人在线观看| 国产亚洲精品美女久久| 欧美特黄一区| 国产精品久久久久av电视剧| 国产亚洲观看| 视频在线观看国产精品| 久久中文亚洲字幕| 国产中文在线播放| 国产精品毛片久久久| 日韩一区精品字幕| 国精品一区二区| 精品国产欧美| 国产精品美女在线观看直播| 日韩一区二区三区精品视频第3页| 国产精品最新| 一区二区精品| 中文在线不卡| 精品一区欧美| 日韩三区在线| 超碰在线99| 久久久精品国产**网站| 久久激情五月激情| 亚洲精品福利| 亚洲一区二区三区在线免费| 日韩精品免费一区二区三区| 高清一区二区三区| 麻豆久久久久久久| 国产精品麻豆成人av电影艾秋| 欧美xxxx中国| 国产欧美日韩一区二区三区在线| 成人在线黄色| 777久久精品| 中文字幕一区二区精品区| 五月天久久网站| 精品一区毛片| av成人国产| 亚洲一区免费| 男女精品网站| 麻豆亚洲精品| 首页亚洲欧美制服丝腿| 老色鬼久久亚洲一区二区| 欧美高清一区| 亚洲经典在线| 性欧美长视频| 亚洲视频二区| 丝袜美腿一区二区三区| 亚洲欧洲午夜| 亚洲香蕉久久| 奇米亚洲欧美| 欧美午夜三级| 国产精品欧美三级在线观看 | 国产精品毛片| 欧美丝袜一区| 三上悠亚国产精品一区二区三区 | 欧美一区二区三区免费看| 亚洲ab电影| 国产黄色一区| 日韩综合一区| 激情综合网站| 亚洲精品欧洲| 视频一区中文字幕精品 | 国产精品玖玖玖在线资源| 日韩av不卡一区二区| 国产精品亚洲欧美日韩一区在线| 不卡在线一区| 美女国产精品| 日本午夜精品久久久| 精品国产亚洲日本| 日韩欧美看国产| 国产视频欧美| 97成人在线| 四虎8848精品成人免费网站| 一区二区三区视频免费观看| 日本欧洲一区二区| 国产亚洲精品美女久久久久久久久久| 蜜桃视频欧美| 欧洲毛片在线视频免费观看| 久久性天堂网| 欧美永久精品| av中文字幕在线观看第一页| 欧美日韩国产精品一区二区亚洲| 中文在线а√在线8| 日韩在线不卡| 黑丝一区二区| 国产亚洲精品精品国产亚洲综合| 亚洲一区二区三区四区五区午夜| 日韩成人精品一区| 日韩电影免费网站| 国产视频一区欧美| 国产毛片精品| 欧美日中文字幕| 日韩国产在线不卡视频| 国产精品成久久久久| 99久久久久| 日本精品另类| 少妇精品导航| 国产日韩欧美一区在线| 天堂中文在线播放| 在线看片一区| 日韩欧美一区二区三区在线视频| 精品久久影院| 亚洲精品1区2区| 久久不卡国产精品一区二区| 亚洲韩日在线| 日本久久二区| 日韩精品诱惑一区?区三区| 国产亚洲精品自拍| 国产精久久久| 亚洲第一精品影视| 国产日产精品_国产精品毛片| 日韩激情视频网站| 日韩久久电影| 久久狠狠久久| 亚洲精品中文字幕乱码| 欧美91在线| 在线精品国产亚洲| 日韩一区二区在线免费| 欧美精品中文字幕亚洲专区| 999久久久精品国产| 国产精品亚洲综合久久| 亚洲国产日韩欧美在线| 美女性感视频久久|