How to create a drag gesture in any direction in Android Jetpack Compose

I want to detect a gesture in @Composable, which will allow me to drag an element across the screen in any direction.

I tried using LongPressDragObserver but after dragging for a bit, it snaps to a single Orientation (either Horizontally or Vertically) and Offset doesn’t change for the other Orientation at all (it will equal to 0 all the time)

Example functionality I want to achieve:
Long press on the FAB and drag it around the screen so that it’s position is constantly under user’s finger.

I’m using Compose 1.0.0-alpha04

Example code which drags in only one direction (thanks to Rafsanjani)

.dragGestureFilter(dragObserver = object : DragObserver { 
  override fun onDrag(dragDistance: Offset): Offset { 
    val newX = dragDistance.x + verticalOffset.value 
    val newY = dragDistance.y + horizontalOffset.value 
    verticalOffset.value = newX 
    horizontalOffset.value = newY 
    return dragDistance 
  } 
})

Answer

You can use Modifier.pointerInput with detectDragGestures to do exactly the same as you want.

Example:

   @Composable
fun Drag2DGestures() {
    var size by remember { mutableStateOf(400.dp) }
    val offsetX = remember { mutableStateOf(0f) }
    val offsetY = remember { mutableStateOf(0f) }
    Box(modifier = Modifier.size(size)){
        Box(
                Modifier
                        .offset { IntOffset(offsetX.value.roundToInt(), offsetY.value.roundToInt()) }
                        .background(Color.Blue)
                        .size(50.dp)
                        .pointerInput(Unit) {
                            detectDragGestures { change, dragAmount ->
                                change.consumeAllChanges()
                                offsetX.value = (offsetX.value + dragAmount.x)
                                        .coerceIn(0f, size.width.toFloat() - 50.dp.toPx())

                                offsetY.value = (offsetY.value + dragAmount.y)
                                        .coerceIn(0f, size.height.toFloat() - 50.dp.toPx())
                            }
                        }
        )
        Text("Drag the box around", Modifier.align(Alignment.Center))
    }
}

will produce this result:

ٍٍٍSorry for the jank/drop in frames, the built-in emulator recorder cannot record 60fps smoothly

enter image description here

Compose version: alpha-11