1

I have such code from here: https://developer.android.com/jetpack/compose/gestures

    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(Color.Red)
                .size(120.dp) // makes it rectangle. wrap_content without it
                .align(Alignment.BottomEnd)
                .pointerInput(Unit) {
                    detectDragGestures { change, dragAmount ->
                        change.consume()
                        offsetX += dragAmount.x
                        offsetY += dragAmount.y
                    }
                }

        ) {
            // todo
        }
    }

So for end side of x I create something like this:

val newOffsetX = if ((offsetX + dragAmount.x) < 0) { offsetX + dragAmount.x } else { 0 }
offsetX = newOffsetX

But how can I found start of x and prevent my draggable box go out of screen? Is there a way to do it for both X and Y?

Vadim Eksler
  • 865
  • 9
  • 24

1 Answers1

2

If you align your draggable box with Alignment.TopStart you can coerce min and max width and height between 0 and parent size - box size

@Composable
private fun DragSample() {

    BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
        var offsetX by remember { mutableStateOf(0f) }
        var offsetY by remember { mutableStateOf(0f) }

        val parentWidth = constraints.maxWidth
        val parentHeight = constraints.maxHeight
        Box(
            Modifier
                .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
                .background(Color.Red)
                .size(120.dp) // makes it rectangle. wrap_content without it
                .align(Alignment.TopStart)
                .pointerInput(Unit) {

                    val boxSize = this.size
                    detectDragGestures { _, dragAmount ->
                        offsetX = (offsetX + dragAmount.x).coerceIn(
                            0f,
                            parentWidth - boxSize.width.toFloat()
                        )
                        offsetY = (offsetY + dragAmount.y).coerceIn(
                            0f,
                            parentHeight - boxSize.height.toFloat()
                        )
                    }
                }

        ) {
            // todo
        }
    }
}

If you wish to start from Alignemnt.BottomEnd you should do it as

@Composable
private fun DragSample() {

    BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
        var offsetX by remember { mutableStateOf(0f) }
        var offsetY by remember { mutableStateOf(0f) }

        val parentWidth = constraints.maxWidth
        val parentHeight = constraints.maxHeight
        Box(
            Modifier
                .offset { IntOffset(offsetX.roundToInt(), offsetY.roundToInt()) }
                .background(Color.Red)
                .size(120.dp) // makes it rectangle. wrap_content without it
                .align(Alignment.BottomEnd)
                .pointerInput(Unit) {

                    val boxSize = this.size
                    detectDragGestures { _, dragAmount ->
                        offsetX = (offsetX + dragAmount.x).coerceIn(
                             boxSize.width.toFloat() -parentWidth,
                            0f
                        )
                        offsetY = (offsetY + dragAmount.y).coerceIn(
                             boxSize.height.toFloat() -parentHeight,
                            0f
                        )
                    }
                }

        ) {
            // todo
        }
    }
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • can I get instead of `val parentWidth = constraints.maxWidth` screenWidth? – Vadim Eksler Aug 10 '22 at 13:42
  • Do you mean how you can get your screenWidth? If, so you can get it from Modifir.onSizeChanged{}. If you set Modifier.fillMaxSize() constraints.maxWidth you get from BoxWithConstraints is screen width. But it doesn't return your Composable size under some conditions – Thracian Aug 10 '22 at 13:48
  • You can check Constraints section of this answer to see what you get from max/min width/height with different modifiers with BoxWithConstraints. https://stackoverflow.com/a/73258726/5457853 – Thracian Aug 10 '22 at 13:50
  • yes, I mean screenWidth, I have root Row with elements inside, one of elements is my box. so I need to get maxWidth from Row, how can I do it? – Vadim Eksler Aug 10 '22 at 13:52
  • If you attach Modifier.onSizeChanged to your Row you will be able to get its dimensions in IntSize – Thracian Aug 10 '22 at 13:53