主要經過6個控制點實現。git
val startPoint = PointF() val endPoint = PointF() val control1 = PointF() val control2 = PointF() val control3 = PointF() val control4 = PointF()
private fun drawWater(canvas: Canvas) { waterPath.apply { reset() moveTo(startPoint) cubicTo(control1, control3, endPoint) cubicTo(control4, control2, startPoint) } canvas.save() // clipOut 出中間的圓 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { canvas.clipOutPath(Path().apply { addCircle(circleX, circleY, circleR, Path.Direction.CW) }) } else { canvas.clipPath(Path().apply { addCircle(circleX, circleY, circleR, Path.Direction.CW) }, Region.Op.DIFFERENCE) } canvas.drawPath(waterPath, waterPaint) canvas.drawCircle(circleX, circleY, circleR, waterPaint) canvas.restore() }
一些擴展函數,方便直接使用 PointF。github
private fun Path.moveTo(p: PointF) { moveTo(p.x, p.y) } private fun Path.lineTo(p: PointF) { lineTo(p.x, p.y) } private fun Path.cubicTo(control1: PointF, control2: PointF, end: PointF) { cubicTo(control1.x, control1.y, control2.x, control2.y, end.x, end.y) } private fun Path.quadTo(control: PointF, end: PointF) { quadTo(control.x, control.y, end.x, end.y) } private fun Canvas.drawPoint(p: PointF, paint: Paint) { drawPoint(p.x, p.y, paint) }
分爲 6 個階段完成canvas
class AnimatorHelper(val target: JumpWater) { private var animDuration = 300L private var animStartDown: ValueAnimator? = null private var animStartJump: ValueAnimator? = null private var animJump: ValueAnimator? = null private var animDown: ValueAnimator? = null private var animTail: ValueAnimator? = null private var animTailReconver: ValueAnimator? = null private var animSet: AnimatorSet? = null internal fun startJump(tailMove: Float, jumpH: Float) { endJump() animStartDown = ValueAnimator.ofFloat(0f, jumpH).apply { addUpdateListener { target.updateStartDown(it.animatedValue as Float) } } animStartJump = ValueAnimator.ofFloat(jumpH, 0f).apply { addUpdateListener { target.updateStartDown(it.animatedValue as Float) } } animJump = ValueAnimator.ofFloat(0f, jumpH).apply { addUpdateListener { target.updateJump(it.animatedValue as Float) } } animDown = ValueAnimator.ofFloat(jumpH, 0f).apply { addUpdateListener { target.updateJump(it.animatedValue as Float) } } animTail = ValueAnimator.ofFloat(0f, tailMove).apply { addUpdateListener { target.updateTail(it.animatedValue as Float) } } animTailReconver = ValueAnimator.ofFloat(tailMove, 0f).apply { addUpdateListener { target.updateTail(it.animatedValue as Float) } } val tailSet = AnimatorSet().apply { playTogether(animJump, animTail) } val tailSetReconver = AnimatorSet().apply { playTogether(animDown, animTailReconver) } animSet = AnimatorSet().apply { playSequentially(animStartDown, animStartJump, tailSet, tailSetReconver) addListener(object : Animator.AnimatorListener { override fun onAnimationRepeat(animation: Animator?) { } override fun onAnimationEnd(animation: Animator?) { mOnAnimEndListener?.onAnimEnd() } override fun onAnimationCancel(animation: Animator?) { } override fun onAnimationStart(animation: Animator?) { } }) start() } } }
具體請看:https://github.com/stefanJi/AndroidView/tree/master/jumpwaterapp