小爱智能音箱亮度调节控件和色温调节控件的自定义实现

Wondershare UniConverter 13_000001.GIF

亮度调节条的实现

image.png





/**
 * Copyright:MicoLauncher
 * Author: liyang 
* Date:2021/8/23 2:08 下午
* Desc:
*/ class VerticalSeekView( context: Context, attributeSet: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : View(context, attributeSet, defStyleAttr, defStyleRes) { constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: Int = 0) : this( context, attributeSet, defStyleAttr, 0 ) constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0) constructor(context: Context) : this(context, null) .... .... .... companion object { const val TAG = "VerticalSeekView:" @JvmStatic @BindingAdapter("data") fun bindData( view: VerticalSeekView, data: DeviceInfoWrapper ) { data.deviceInfo.apply { when (data.modelInfo.deviceType) { DeviceTypeDic.DT_LIGHT_LIGHT.deviceType, DeviceTypeDic.DT_LIGHT_MIRROR.deviceType, DeviceTypeDic.DT_LIGHT_NIGHT_LIGHT.deviceType -> { view.showIcon = true view.deviceTypeIcon = if (currentStatus) { R.drawable.sh_ic_light_icon_on } else { R.drawable.sh_ic_light_icon_off } } DeviceTypeDic.DT_ENV_HEATER.deviceType -> { view.showIcon = true view.deviceTypeIcon = if (currentStatus) { R.drawable.sh_ic_heater_temperature_on } else { R.drawable.sh_ic_heater_temperature_off } view.foregroundColor = ContextCompat.getColor( view.context, if (currentStatus) R.color.sh_miot_heater_foreground_color else R.color.sh_miot_heater_foreground_color_off ) } } } } } .... .... .... var volume: Double = 0.0 set(value) { if (value in 0.0..1.0 && field != value) { field = value volumeChangeListener?.onVolumeChanged(value) refresh() } } var volumeChangeListener: OnVolumeChangeListener? = null private val minTouchSlop by lazy { ViewConfiguration.get(context).scaledTouchSlop } init { val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.VerticalSeekView) radius = typedArray.getDimensionPixelOffset(R.styleable.VerticalSeekView_radius, 0).let { var num = it if (it < 0) { num = 0 } num } deviceTypeIcon = typedArray.getResourceId( R.styleable.VerticalSeekView_deviceTypeIcon, R.drawable.sh_ic_iot_lamp ) bitmap = ContextCompat.getDrawable(context, deviceTypeIcon)?.toBitmap() underlyingColor = typedArray.getColor( R.styleable.VerticalSeekView_underlyingLayerColor, context.getColor(R.color.sh_miot_seek_view_background_color) ) foregroundColor = typedArray.getColor( R.styleable.VerticalSeekView_foregroundLayerColor, context.getColor(R.color.sh_miot_seek_view_foreground_color) ) volume = (typedArray.getFloat(R.styleable.VerticalSeekView_volume, 0.0f) .takeIf { it >= 0.0f || it <= 100.0f } ?: 0.0f) .toDouble() startColor = typedArray.getColor(R.styleable.VerticalSeekView_startColor, foregroundColor) endColor = typedArray.getColor(R.styleable.VerticalSeekView_endColor, foregroundColor) canDrag = typedArray.getBoolean(R.styleable.VerticalSeekView_canDrag, true) paint.isAntiAlias = true paint.isDither = true typedArray.recycle() } @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent?): Boolean { if (!canDrag) return super.onTouchEvent(event) when (event?.action) { MotionEvent.ACTION_DOWN -> { startX = event.x startY = event.y downTimestamp = System.currentTimeMillis() L.smarthome.d("$TAG onTouchEvent ACTION_DOWN downX=$startX,downY=$startY,minTouchSlop=$minTouchSlop") volumeChangeListener?.onVolumeChangedBegin(volume) startVolume = volume return true } MotionEvent.ACTION_MOVE -> { currentX = event.x currentY = event.y val offsetX = startX - currentX val offsetY = startY - currentY if (abs(offsetY) > abs(offsetX)) {//纵向滑动时,请求RecyclerView不拦截事件 parent.requestDisallowInterceptTouchEvent(true) if (abs(offsetY) > minTouchSlop) { if (!isFistMoveAction) { volume = (offsetY / height).plus(startVolume).let { var newVolume = it if (it >= 1) { newVolume = 1.0 } if (it <= 0) { newVolume = 0.0 } newVolume } isVolumeChange = true L.smarthome.d("$TAG onTouchEvent ACTION_MOVE setVolume=$volume") return true } isFistMoveAction = false } } lastX = currentX lastY = currentY } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { currentX = 0f currentY = 0f lastY = 0f lastX = 0f isFistMoveAction = true parent.requestDisallowInterceptTouchEvent(false) L.smarthome.d("$TAG ${if (event.action == MotionEvent.ACTION_UP) "ACTION_UP" else "ACTION_CANCEL"} requestDisallowInterceptTouchEvent:false") val isLongClick = (System.currentTimeMillis() - downTimestamp) >= ViewConfiguration.getLongPressTimeout() if (event.action == MotionEvent.ACTION_UP && !isVolumeChange && !isLongClick) { performClick() } if (isVolumeChange) { isVolumeChange = false } volumeChangeListener?.onVolumeChangedEnd(isVolumeChange, volume) } } return super.onTouchEvent(event) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { layerId = saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null) //画底层背景色 onDrawUnderlyingLayer(this) //画上层填充色 onDrawForegroundLayer(this) //画小横条 onDrawHandler(this) //画底部的icon onDrawIcon(this) restoreToCount(layerId) } } private fun onDrawIcon(canvas: Canvas) { if (!showIcon)return bitmap?.apply { L.smarthome.d("$TAG,width=$width,height=$height") canvas.drawBitmap(this, Rect(0, 0, width, height), destRect, null) } } private fun onDrawHandler(canvas: Canvas) { if (!canDrag) return rectF.left = ((width - 40.toPx()) / 2).toFloat() rectF.top = (canvas.height - canvas.height * volume + 8.toPx()).toFloat() rectF.right = (width / 2 + 17).toFloat() rectF.bottom = rectF.top.minus(4) paint.color = ContextCompat.getColor(context, R.color.black_12_transparent) canvas.drawRoundRect(rectF, 1.5f, 1.5f, paint) } private fun onDrawUnderlyingLayer(canvas: Canvas) { paint.style = Paint.Style.FILL paint.color = underlyingColor rectF.left = 0f rectF.top = 0f rectF.right = canvas.width.toFloat() rectF.bottom = canvas.height.toFloat() canvas.drawRoundRect(rectF, radius.toFloat(), radius.toFloat(), paint) } private fun onDrawForegroundLayer(canvas: Canvas) { paint.style = Paint.Style.FILL paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP) val top = (canvas.height - canvas.height * volume).toFloat() val bottom = canvas.height.toFloat() if (startColor != foregroundColor || endColor != foregroundColor) { val gradient = LinearGradient( (width / 2).toFloat(), top, (width / 2).toFloat(), bottom, startColor, endColor, Shader.TileMode.CLAMP ) paint.shader = gradient } else { paint.color = foregroundColor } rectF.left = 0f rectF.top = top rectF.right = canvas.width.toFloat() rectF.bottom = bottom canvas.drawRect(rectF, paint) paint.xfermode = null paint.shader = null } private fun refresh() { if (Looper.myLooper() != Looper.getMainLooper()) { postInvalidate() } else { invalidate() } } } interface OnVolumeChangeListener { fun onVolumeChangedBegin(volume: Double) fun onVolumeChanged(volume: Double) fun onVolumeChangedEnd(flag: Boolean, volume: Double) }

色温调节条的实现

2022.02.14-11.49.56.png
package com.xiaomi.smarthome.ui.widgets



/**
 * Copyright:MicoLauncher
 * Author: liyang 
* Date:2021/8/23 2:08 下午
* Desc:
*/ class VerticalSeekView2( context: Context, attributeSet: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : View(context, attributeSet, defStyleAttr, defStyleRes) { constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: Int = 0) : this( context, attributeSet, defStyleAttr, 0 ) constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0) constructor(context: Context) : this(context, null) ...... ...... var volume: Double = 0.0 set(value) { if (value in 0.0..1.0 && field != value) { field = value refresh() volumeChangeListener?.onVolumeChanged(value) } } var volumeChangeListener: OnVolumeChangeListener? = null ...... ...... ...... init { val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.VerticalSeekView2) radius = typedArray.getDimensionPixelOffset(R.styleable.VerticalSeekView2_radius, 0).let { var num = it if (it < 0) { num = 0 } num } startColor = typedArray.getColor(R.styleable.VerticalSeekView2_startColor, Color.WHITE) endColor = typedArray.getColor(R.styleable.VerticalSeekView2_endColor, Color.BLUE) volume = (typedArray.getFloat(R.styleable.VerticalSeekView2_volume, 0.0f) .takeIf { it >= 0.0f || it <= 100.0f } ?: 0.0f) .toDouble() paint.isAntiAlias = true paint.isDither = true typedArray.recycle() } @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(event: MotionEvent?): Boolean { when (event?.action) { MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> { if (event.action == MotionEvent.ACTION_DOWN) { parent.requestDisallowInterceptTouchEvent(true) } currentX = event.y currentY = event.x val offsetX = lastX - currentX val offsetY = lastY - currentY if (abs(offsetX) < abs(offsetY)) {//纵向滑动时,请求RecyclerView不拦截事件 parent.requestDisallowInterceptTouchEvent(true) } volume = ((height - currentX) / height).toDouble().let { var newVolume = it if (it >= 1) { newVolume = 1.0 } if (it <= 0) { newVolume = 0.0 } newVolume } lastX = currentX lastY = currentY L.smarthome.d("$TAG onTouchEvent currentX=$currentX,currentY=$currentY") return true } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { currentX = 0f currentY = 0f lastY = 0f lastX = 0f parent.requestDisallowInterceptTouchEvent(false) L.smarthome.d("${TAG}requestDisallowInterceptTouchEvent:false") } } return super.onTouchEvent(event) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { layerId = saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null) onDrawUnderlyingLayer(this) onDrawHandler(this) restoreToCount(layerId) } } private fun onDrawHandler(canvas: Canvas) { rectF.left = 0f rectF.top = (canvas.height - canvas.height * volume).toFloat().let { var newVal=it if (it>=canvas.height+48.toPx()){ newVal=(canvas.height+48.toPx()).toFloat() }else if (it<=48.toPx()){ newVal=48.toPx().toFloat() } newVal } rectF.right = width.toFloat() rectF.bottom = rectF.top.minus(48.toPx()) paint.color = Color.WHITE canvas.drawRoundRect(rectF, 26f, 26f, paint) } private fun onDrawUnderlyingLayer(canvas: Canvas) { paint.style = Paint.Style.FILL val gradient = LinearGradient((width / 2).toFloat(), 0f, (width / 2).toFloat(), height.toFloat(),startColor,endColor,Shader.TileMode.REPEAT) paint.shader=gradient rectF.left = 0f rectF.top = 0f rectF.right = canvas.width.toFloat() rectF.bottom = canvas.height.toFloat() canvas.drawRoundRect(rectF, radius.toFloat(), radius.toFloat(), paint) paint.shader=null } private fun refresh() { if (Looper.myLooper() != Looper.getMainLooper()) { postInvalidate() } else { invalidate() } } }

你可能感兴趣的:(小爱智能音箱亮度调节控件和色温调节控件的自定义实现)