I have a sample composable
function that's contains a rectangle
drawn in a Canvas
composable
. The detectTapGestures
within the pointerInput
Modifier
is used to detect whenever any point in the Canvas
is touched, specifically within the rectangle
coordinates.
@Composable
fun Sample() {
var rectangleCoordinates by remember{ mutableStateOf(Rect.Zero) }
Canvas(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures {
if (rectangleCoordinates.contains(it)) {
Log.d(topBarTag, "rectangle touched")
}
}
}
){
val rectSize = Size(40.dp.toPx(), 40.dp.toPx())
rectangleCoordinates = Rect(center, rectSize)
drawRect(
topLeft = center,
size = rectSize,
color = Color.Blue
)
}
}
Is there a way to show a ripple
on the rectangle
when it's touched?
First, i changed from tap to
awaitFirstDown
to detect initial contact and towaitForUpOrCancellation
to detect when user lifts last pointer or moves out of Canvas coordinates. You can change waitForUpOrCancellation with custom behavior. I explain in this answer how to create your own onTouchDown implentation with Jetpack Compose. You can break loop with contains check if you wish toSecond, we need to animate radius and color of circle from touch position.
isTouched to detect whether we touched rect so we can play a reverse animation for canceling ripple.
clipRect is for bounding ripple to Canvas or your rectangle coordinates. You can customize color, alpha limit and more importantly keyFrames to have better ripple version if you wish to
Result
The rectangle on top is actual ripple with Modifier.clickable
Second one is the one from Canvas.
To complete circle ripple animations you can turn each into a class add to a class when pressed and run animations from a list and remove each one when animation is over or pointer is up to full length ripples unlike in Canvas that stops propagating because animatable.animateTo cancels previous one.