I don't even know where to begin, nothing similar was ever implemented in Jetpack Compose. How can I make a composable detect 2-finger swipe (or drag) gesture ? Preferably (but not necessarily) without consuming them
Asked
Active
Viewed 652 times
2 Answers
0
You can achieve multitouch by using transformable
modifier on your composable. Something like this:
@Composable
fun TransformableSample() {
// set up all transformation states
var scale by remember { mutableStateOf(1f) }
var rotation by remember { mutableStateOf(0f) }
var offset by remember { mutableStateOf(Offset.Zero) }
val state = rememberTransformableState { zoomChange, offsetChange, rotationChange ->
scale *= zoomChange
rotation += rotationChange
offset += offsetChange
}
Box(
Modifier
// apply other transformations like rotation and zoom
// on the pizza slice emoji
.graphicsLayer(
scaleX = scale,
scaleY = scale,
rotationZ = rotation,
translationX = offset.x,
translationY = offset.y
)
// add transformable to listen to multitouch transformation events
// after offset
.transformable(state = state)
.background(Color.Blue)
.fillMaxSize()
)
}
More info on Compose gestures can be found here.

Talha Mir
- 1,228
- 11
- 19
-
1I know about this one, but how is it possible to track two panning values at once ? The panning (offset values) are already exposed after a single pointer (finger) is swiping, but I need it for two. And also, I need to know the direction. – yuroyami Feb 20 '23 at 14:25
0
I came up with a solution that works consistently. I had to edit the source code for the detectVerticalDragGestures to count the pointers being used, then return the count as parameter in 'onVerticalDrag' like this:
suspend fun PointerInputScope.detectAdvancedVerticalDragGestures(
onDragStart: (Offset) -> Unit = { },
onDragEnd: () -> Unit = { },
onVerticalDrag: (event: PointerEvent, change: PointerInputChange, dragAmount: Float, pointerCount: Int) -> Unit
) {
awaitEachGesture {
val down = awaitFirstDown(requireUnconsumed = false)
var overSlop = 0f
val drag = awaitVerticalPointerSlopOrCancellation(down.id, down.type) { change, over ->
change.consume()
overSlop = over
}
if (drag != null) {
onDragStart.invoke(drag.position)
//Here's the block of code I added to return count
//By the way, IM not sure which pointer returns the drag amount
//but i think it returns the drag amount for the pointer
//that had the first down event (that touched the screen first)
val changes = currentEvent.changes.takeLast(2)
val count: Int = if (changes.size == 1) {
1
} else if (changes.size == 2) {
if (changes.last().id != changes.first().id) {
2
} else {
1
}
} else {
0
}
onVerticalDrag.invoke(currentEvent, drag, overSlop, count)
if (verticalDrag(drag.id) {
onVerticalDrag(currentEvent, it, it.positionChange().y, count)
it.consume()
}
) {
onDragEnd()
}
}
}
}
This should also work for detectDragGestures or detectHorizontalDragGestures if you edit the same way I did. Hope it helped.

yuroyami
- 814
- 6
- 24