1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
| class RingView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr), AnimatorUpdateListener, Animator.AnimatorListener { private val bgRing = BitmapFactory.decodeResource(resources, R.mipmap.bg_ring) private val targetWidth = (bgRing.width * 1.4).toInt() private val targetHeight = (bgRing.height * 1.4).toInt() private val radius = targetWidth / 2 private var xPos = 0 private var yPos = 0 private val strokeWidth = 6f private val paint = Paint() private var animator: ValueAnimator? = null private var isDown = true
private var startY = 0 private var endY = 0 private var maxDragY = 0 private val accelerateInterpolator = AccelerateInterpolator() private val decelerateInterpolator = DecelerateInterpolator() private val srcRingRect = Rect(0, 0, bgRing.width, bgRing.height) private val dstRingRect = Rect() private var isDrag = false private var curDragY = 0f private var lastDragY = 0f private var stopAnimate = false private var lastMoveY = 0f private var ratio = 0f private var padding = 20 init { paint.color = resources.getColor(R.color.colorPrimary) paint.isAntiAlias = true postDelayed({ startAnimation() }, 1000) }
override fun onDraw(canvas: Canvas) { super.onDraw(canvas) if (animator == null) { startY = canvas.height / 2 - radius / 2 endY = canvas.height / 2 yPos = startY maxDragY = endY + endY / 2 xPos = canvas.width / 2 - radius } drawLine(canvas) drawRing(canvas) }
private fun drawRing(canvas: Canvas) { dstRingRect.left = xPos dstRingRect.top = yPos dstRingRect.right = xPos + targetWidth dstRingRect.bottom = yPos + targetHeight canvas.drawBitmap(bgRing, srcRingRect, dstRingRect, paint) }
override fun onAnimationUpdate(animation: ValueAnimator) { yPos = animation.animatedValue as Int ratio = (yPos - startY).toFloat() / (maxDragY - startY) invalidate() }
private fun drawLine(canvas: Canvas) { paint.strokeWidth = strokeWidth - 3 * ratio canvas.drawLine((xPos + radius).toFloat(), 0f, (xPos + radius).toFloat(), (yPos + 2).toFloat(), paint) }
private fun initAnimator(start: Int, end: Int) { animator = ValueAnimator.ofInt(start, end) animator?.duration = 1000 animator?.interpolator = accelerateInterpolator animator?.addUpdateListener(this) animator?.addListener(this) }
private fun startAnimation() { initAnimator(startY, endY) isDown = true animator?.start() }
override fun onAnimationRepeat(animation: Animator) {} override fun onAnimationStart(animation: Animator) {} override fun onAnimationEnd(animation: Animator) { if (!stopAnimate) { val vAnimation = animation as ValueAnimator isDown = !isDown if (isDown) { vAnimation.setIntValues(startY, endY) vAnimation.interpolator = accelerateInterpolator } else { vAnimation.setIntValues(endY, startY) vAnimation.interpolator = decelerateInterpolator } vAnimation.start() } }
override fun onAnimationCancel(animation: Animator) {} override fun onTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { isDrag = dstRingRect.plus(padding).contains(event.x.toInt(), event.y.toInt()) if (isDrag) { lastDragY = event.y if (animator != null && animator!!.isRunning) { stopAnimate = true animator?.cancel() } lastMoveY = (yPos + radius).toFloat() } } MotionEvent.ACTION_UP -> { back() lastMoveY = 0f isDrag = false } MotionEvent.ACTION_MOVE -> { curDragY = event.y if (isDrag && curDragY - lastDragY > 10) { val diffY = curDragY - lastMoveY Log.i(TAG, "diffY: $diffY" ) if (diffY > 0){ if (curDragY < maxDragY){ val targetY = curDragY.toInt() Log.i(TAG, "maxLength: ${maxDragY - lastDragY}" ) ratio = (targetY - lastDragY) / (maxDragY - lastDragY) yPos = (yPos + diffY * (1 - ratio)).toInt() Log.i(TAG, "add: ${diffY * (1 - ratio)}, diffY:${diffY} ratio:${(1 - ratio)}" ) } else { ratio = 1f isDrag = false }
invalidate() } lastMoveY = curDragY } } } return true }
private fun back() { if (animator != null && !animator!!.isRunning) { animator?.setIntValues(yPos, startY) animator?.interpolator = decelerateInterpolator stopAnimate = false animator?.start() isDown = false } }
}
|