我目前正在创建一个Android视图,在用户点击它时,我将在点击的坐标周围显示一种涟漪效果。
但是我不确定如何实现。我的第一个想法是使缓存失效,并每次使圆圈变大,但是这样做似乎不合适也不高效。
如果有人之前遇到过同样的问题并且愿意分享一些如何实现的技巧,那将不胜感激。
我目前正在创建一个Android视图,在用户点击它时,我将在点击的坐标周围显示一种涟漪效果。
但是我不确定如何实现。我的第一个想法是使缓存失效,并每次使圆圈变大,但是这样做似乎不合适也不高效。
如果有人之前遇到过同样的问题并且愿意分享一些如何实现的技巧,那将不胜感激。
我终于找到了一个解决方案。虽然不是完美的,但现在它能够工作。
这是我编写的代码。基本上当我需要它时,我将布尔值更改为“true”,因此我的onDraw
函数知道它必须执行drawFingerPrint
函数。
另一方面,drawFingerPrint
函数只是在每次迭代之间绘制一个越来越大的圆形,直到达到所需的直径。
private fun drawFingerPrint(canvas: Canvas) {
canvas.drawCircle(pointerX, pointerY, radius, paint)
if(radius<= 100F){
radius+=10F
invalidate()
}
else{
radius = 0F
drawAroundFinger = false
invalidate()
}
}
如@Matthieu所提到的,您需要在画布上绘制圆形并使视图失效。这里我提供一个更完整的示例。
所以我们有一个开放类RippleView
:
open class RippleView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private var rippleX: Float? = null
private var rippleY: Float? = null
private var rippleRadius: Float? = null
var maxRippleRadius: Float = 100f // Retrieve from resources
var rippleColor: Int = 0x88888888.toInt()
private val ripplePaint = Paint().apply {
color = rippleColor
}
private val animationExpand = object : Runnable {
override fun run() {
rippleRadius?.let { radius ->
if (radius < maxRippleRadius) {
rippleRadius = radius + maxRippleRadius * 0.1f
invalidate()
postDelayed(this, 10L)
}
}
}
}
private val animationFade = object : Runnable {
override fun run() {
ripplePaint.color.let { color ->
if (color.alpha > 10) {
ripplePaint.color = color.adjustAlpha(0.9f)
invalidate()
postDelayed(this, 10L)
} else {
rippleX = null
rippleY = null
rippleRadius = null
invalidate()
}
}
}
}
fun startRipple(x: Float, y: Float) {
rippleX = x
rippleY = y
rippleRadius = maxRippleRadius * 0.15f
ripplePaint.color = rippleColor
animationExpand.run()
}
fun stopRipple() {
if (rippleRadius != null) {
animationFade.run()
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val x = rippleX ?: return
val y = rippleY ?: return
val r = rippleRadius ?: return
canvas.drawCircle(x, y, r, ripplePaint)
}
}
fun Int.adjustAlpha(factor: Float): Int =
(this.ushr(24) * factor).roundToInt() shl 24 or (0x00FFFFFF and this)
inline val Int.alpha: Int
get() = (this shr 24) and 0xFF
RippleView
扩展任何自定义视图,并在获取ACTION_DOWN
时使用startRipple
方法,以及在获取ACTION_UP
时使用stopRipple
方法:class ExampleView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : RippleView(context, attrs), View.OnTouchListener {
init {
setOnTouchListener(this)
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
if (isInsideArea(event.x, event.y)) {
startRipple(event.x, event.y)
}
}
MotionEvent.ACTION_UP -> {
stopRipple()
}
}
return false
}
private fun isInsideArea(x: Float, y: Float): Boolean {
TODO("Not yet implemented")
}
}