2

I have a Box composeable that uses detectDragGestures to enable dragging on the screen (ref: Gestures | Compose | Android Developers).

@Composable
private fun DraggableBlock() {
    Box(modifier = Modifier.fillMaxSize()) {
        var offsetX by remember { mutableStateOf(0f) }
        var offsetY by remember { mutableStateOf(0f) }

        Box(
            Modifier
                .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
                .background(MaterialTheme.colorScheme.primary)
                .size(150.dp)
                .pointerInput(Unit) {
                    detectDragGestures { change, dragAmount ->
                        change.consume()
                        offsetX += dragAmount.x
                        offsetY += dragAmount.y
                    }
                }
        )
    }
}

Right now I am able to drag the box anywhere on the screen—even outside of the parent Box. This makes sense because I'm just giving it the raw X and Y coordinates.

How do I limit the dragging to within the bounds of the parent Box?

Attempts to Solve

clipToBounds()

I tried clipToBounds() on the parent box as detailed in https://stackoverflow.com/a/72651257/11809808 but that's not what I'm looking for. I want the box to stop at the boundaries, not get clipped.

Ryan Payne
  • 5,249
  • 4
  • 28
  • 69

1 Answers1

1

You can calculate the constraint using the size of the parent Box and the draggable Box.

In the parent Box:

    var size by remember { mutableStateOf(IntSize.Zero) }
    Box(modifier = Modifier
        .fillMaxSize()
        .onSizeChanged {
            size = it
        }
    )

In the draggable Box:

val boxSize = 150.dp

Box(
    Modifier
        .offset {
            IntOffset(offsetX.roundToInt().coerceIn(0,size.width-boxSize.roundToPx()),
            offsetY.roundToInt().coerceIn(0,size.height-boxSize.roundToPx()))
        }
        .background(MaterialTheme.colorScheme.primary)
        .size(boxSize)
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841