I am trying to create an icon button which invokes a lambda when tapped, but if the user presses the button and holds it, then also the lambda should get continuously invoked in fixed intervals.
@Composable
fun MyIconButton(
someLambda: () -> Unit
) {
IconButton(onClick = someLambda) {
Icon(
// painter and content description
)
}
}
Here what I want is that when user presses the button, someLambda
should get invoked (which is working fine). Additionally, I also want to invoke someLambda
repeatedly (with a gap of 500ms between two invocations) until the user releases the button.
Basically what I want is to detect something like the KeyUp and KeyDown events.
How to achieve this?
CodePudding user response:
You can use Modifier.pointerInpteropFilter
for this:
var job by remember {
mutableStateOf<Job?>(null)
}
val scope = rememberCoroutineScope()
Icon(
imageVector = Icons.Filled.Favorite,
modifier = Modifier
.requiredSize(96.dp)
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_DOWN -> {
job = scope.launch {
while (true) {
// trigger event
Log.d("foo", "Trigger event")
delay(500L)
}
}
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> {
job?.cancel()
job = null
}
}
true
},
contentDescription = "Sample icon"
)
Another solution is to use Modifier.pointerInput
:
val scope = rememberCoroutineScope()
Icon(
imageVector = Icons.Filled.Favorite,
modifier = Modifier
.requiredSize(96.dp)
.pointerInput(Unit) {
while (true) {
awaitPointerEventScope {
awaitFirstDown()
val job = scope.launch {
while (true) {
// trigger event
Log.d("foo", "Trigger event")
delay(500L)
Log.d("foo", "After delay")
}
}
waitForUpOrCancellation()
job.cancel()
}
}
},
contentDescription = "Sample icon"
)
CodePudding user response:
I'll update the answer by tomorrow, but for now, this should suit your use case
Modifier.pointerInput(Unit) {
detectTapGestures(
onPress = { /* Called when the gesture starts */ },
onDoubleTap = { /* Called on Double Tap */ },
onLongPress = { /* Called on Long Press */ },
onTap = { /* Called on Tap */ }
)
}
CodePudding user response:
I solved the problem using this Modifier.pointerInput
on my Icon
.
Modifier.pointerInput(true) {
detectTapGestures(onPress = {
coroutineScope {
val job = launch {
while (true) {
// Invoke lambda
delay(500)
}
}
tryAwaitRelease()
job.cancel()
}
})
}
As per the documentation,
onPress
is called when the press is detected andPressGestureScope.tryAwaitRelease
can be used to detect when pointers have released or the gesture was canceled.