Question
How to create a draggable and rotatable box in Jetpack Compose?
I'm working on a Jetpack Compose application and I want to create a Box
that can be both dragged and rotated using mouse interactions. I should be able to click and drag the entire Box to move it around the screen. also I want to add a small handle at the top-center of the Box. When I drag this handle, the Box
should rotate around its center.
Here's what I've tried so far:
@Composable
fun DragRotateBox() {
var rotation by remember { mutableStateOf(0f) }
var position by remember { mutableStateOf(Offset.Zero) }
var initialTouch = Offset.Zero
val boxSize = 100.dp
val handleSize = 20.dp
val boxSizePx = with(LocalDensity.current) { boxSize.toPx() }
val center = Offset(boxSizePx, boxSizePx)
// Main Box
Box(
modifier = Modifier
.graphicsLayer(
rotationZ = rotation,
translationX = position.x,
translationY = position.y
)
.background(Color.Blue)
.size(boxSize)
.pointerInput(Unit) {
detectDragGestures(
onDrag = {change, dragAmount ->
change.consume()
position += dragAmount
}
)
}
) {
// Rotation handler
Box(
modifier = Modifier
.size(handleSize)
.background(Color.Red)
.align(Alignment.TopCenter)
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { offset ->
initialTouch = offset
},
onDrag = { change, dragAmount ->
change.consume()
val angle = calculateRotationAngle(center, initialTouch, change.position)
rotation += angle
}
)
}
)
}
}
// Generated by ChatGPT!
fun calculateRotationAngle(pivot: Offset, initialTouch: Offset, currentTouch: Offset): Float {
val initialVector = initialTouch - pivot
val currentVector = currentTouch - pivot
val initialAngle = atan2(initialVector.y, initialVector.x)
val currentAngle = atan2(currentVector.y, currentVector.x)
return Math.toDegrees((currentAngle - initialAngle).toDouble()).toFloat()
}
The dragging and the rotation work fine when implemented alone, but when I try to combine both dragging and rotating, the interactions do not work as expected.
Here is a demo of the issue:
I'm sure I'm missing something. Can anyone please help me with this?