123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- package com.develop.common.widget
- import android.content.Context
- import android.graphics.Canvas
- import android.graphics.Paint
- import android.graphics.Path
- import android.util.AttributeSet
- import android.util.TypedValue
- import android.view.MotionEvent
- import android.view.View
- import com.develop.base.ext.isBrand011A
- import com.develop.base.ext.isBrand062
- import com.develop.base.ext.isNightTheme
- import kotlin.math.*
- class RingControlView @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
- ) : View(context, attrs, defStyleAttr) {
- private val fillPath = Path()
- private val stubPath = Path()
- private val ringPaint = Paint(Paint.ANTI_ALIAS_FLAG) //圆点
- private val extraPaint = Paint(Paint.ANTI_ALIAS_FLAG) //圆弧
- private val is062 = isBrand062()
- private val is011 = isBrand011A()
- private val ringStrokeWidth = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 7f, context.resources.displayMetrics
- )
- private val controlDotRadius = TypedValue.applyDimension(
- TypedValue.COMPLEX_UNIT_DIP, 8f, context.resources.displayMetrics
- )
- private val ringPadding = (controlDotRadius * 2 - ringStrokeWidth) / 2
- private var progress: Float = 0.5f
- private var controlling = false
- private var controlDotX = 0.0
- private var controlDotY = 0.0
- var onRingViewListener: OnRingViewListener? = null
- init {
- ringPaint.color = 0xffE60012.toInt()
- ringPaint.style = Paint.Style.STROKE
- ringPaint.strokeCap = Paint.Cap.ROUND
- ringPaint.strokeWidth = ringStrokeWidth
- }
- private var minPro = 0f
- private var maxPro = 100f
- private var isCanTouch = true
- override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
- super.onSizeChanged(w, h, oldw, oldh)
- stubPath.reset()
- stubPath.addArc(
- ringStrokeWidth / 2 + ringPadding,
- ringStrokeWidth / 2 + ringPadding,
- w.toFloat() - ringStrokeWidth / 2 - ringPadding,
- h.toFloat() - ringStrokeWidth / 2 - ringPadding,
- -240f, 300f
- )
- rebuildFillData(progress)
- }
- override fun onDraw(canvas: Canvas) {
- super.onDraw(canvas)
- val nightTheme = isNightTheme()
- if (nightTheme) {
- extraPaint.color = 0x00000000
- } else {
- extraPaint.color = 0x60ffffff
- }
- val radius = width / 2f - ringStrokeWidth - ringPadding
- canvas.drawCircle(width / 2f, height / 2f, radius, extraPaint)
- ringPaint.color = 0xffffffff.toInt()
- canvas.drawPath(stubPath, ringPaint)
- if (isNightTheme()) {
- ringPaint.color = if (is011) 0xffD51317.toInt() else 0xffE03E52.toInt()
- } else {
- if (is062){
- ringPaint.color = 0xffDAE343.toInt()
- }else{
- ringPaint.color = 0xffE60012.toInt()
- }
- }
- canvas.drawPath(fillPath, ringPaint)
- extraPaint.color = if (nightTheme) if (is011) 0xffD51317.toInt() else 0xffDF3F54.toInt() else if (is062) 0xffDAE343.toInt() else 0xffFFA627.toInt()
- // -150 ~ 150
- val angle = 300.0 * progress - 150.0
- val dotRadius = width / 2 - ringPadding - ringStrokeWidth / 2
- val dotX = sin(Math.toRadians(angle)) * dotRadius + width / 2
- val dotY = height / 2 - cos(Math.toRadians(angle)) * dotRadius
- canvas.drawCircle(
- dotX.toFloat(), dotY.toFloat(), controlDotRadius, extraPaint
- )
- }
- private fun rebuildFillData(percent: Float) {
- val w = width
- val h = height
- fillPath.reset()
- fillPath.addArc(
- ringStrokeWidth / 2 + ringPadding,
- ringStrokeWidth / 2 + ringPadding,
- w.toFloat() - ringStrokeWidth / 2 - ringPadding,
- h.toFloat() - ringStrokeWidth / 2 - ringPadding,
- -240f, percent * 300f
- )
- // -150 ~ 150
- val angle = 300.0 * percent - 150.0
- val dotRadius = width / 2 - ringPadding - ringStrokeWidth / 2
- controlDotX = sin(Math.toRadians(angle)) * dotRadius + width / 2
- controlDotY = height / 2 - cos(Math.toRadians(angle)) * dotRadius
- }
- override fun onTouchEvent(event: MotionEvent): Boolean {
- if (!isCanTouch) return false
- val moveX = event.x
- val moveY = event.y
- val distance = sqrt(
- (controlDotX - moveX) * (controlDotX - moveX) + (controlDotY - moveY) * (controlDotY - moveY)
- )
- when (event.action) {
- MotionEvent.ACTION_DOWN -> {
- if (distance > 60) {
- return super.onTouchEvent(event)
- }
- controlling = true
- calculateCurrentPercent(moveX, moveY)
- return true
- }
- MotionEvent.ACTION_MOVE -> {
- if (controlling) {
- calculateCurrentPercent(moveX, moveY)
- return true
- }
- }
- MotionEvent.ACTION_UP -> {
- if (controlling) {
- controlling = false
- calculateCurrentPercent(moveX, moveY)
- return true
- }
- }
- }
- return super.onTouchEvent(event)
- }
- private fun calculateCurrentPercent(moveX: Float, moveY: Float) {
- val distance = sqrt(
- (width / 2.0 - moveX) * (width / 2.0 - moveX) + (height / 2.0 - moveY) * (height / 2.0 - moveY)
- )
- val px = width / 2f - moveX
- val degree = acos(px / distance)
- var angle = Math.toDegrees(degree)
- if (moveY > height / 2) {
- angle = if (moveX < width / 2) {
- -angle
- } else {
- 360 - angle
- }
- }
- val percent = (angle + 60f) / 300f
- if (abs(percent - this.progress) > 0.2f) {
- return
- }
- setProgress(percent.toFloat())
- onRingViewListener?.onProgressChange((progress * (maxPro - minPro) + minPro).toInt())
- }
- private fun setProgress(progress: Float) {
- if (progress > 1) {
- this.progress = 1f
- } else if (progress < 0) {
- this.progress = 0f
- } else {
- this.progress = progress
- }
- if (width > 0) {
- rebuildFillData(this.progress)
- }
- postInvalidate()
- }
- fun updateProgress(value: Int) {
- progress = (value - minPro) / (maxPro - minPro)
- setProgress(progress)
- }
- /**
- * 设置范围默认0-100
- *
- */
- fun setRange(min: Float, max: Float) {
- minPro = min
- maxPro = max
- }
- fun setCanTouch(touch: Boolean) {
- isCanTouch = touch
- }
- interface OnRingViewListener {
- fun onProgressChange(progress: Int)
- }
- }
|