如何在 Jetpack Compose 中创建可拖动和可旋转的框?

问题描述 投票:0回答:1

我正在开发 Jetpack Compose 应用程序,我想创建一个可以使用鼠标交互进行拖动和旋转的

Box
。我应该能够单击并拖动整个框以将其在屏幕上移动。我还想在盒子的顶部中心添加一个小手柄。当我拖动此手柄时,
Box
应绕其中心旋转。

这是我迄今为止尝试过的:

@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()
}

单独实现时,拖动和旋转工作正常,但是当我尝试将拖动和旋转结合起来时,交互无法按预期工作。

这是该问题的演示:

enter image description here

我确信我错过了一些东西。谁能帮我解决这个问题吗?

android kotlin android-jetpack-compose rotation compose-desktop
1个回答
0
投票

当您应用

graphicsLayer
修改器旋转蓝色框时,所有以下修改器的坐标也会受到影响。当盒子旋转 180° 时,上变为下,左变为右:移动盒子现在已反转。

通常有两种方法可以解决这个问题:

  1. 使用与
    pointerInput
    类似的函数将蓝色框的
    calculateRotationAngle
    接收到的坐标翻译回来。
  2. pointerInput
    混乱坐标之前应用 graphicsLayer
我更喜欢解决方案 2,因为它更容易。但请注意:如果您只是将蓝色框的

pointerInput

 移动到修改器链的前面,则只有当您单击该框左上角的 
original 位置时才会检测到拖动手势。这是因为不仅旋转尚未应用(预期的目的),位置平移也尚未应用,因此从 pointerInput
 的角度来看,盒子从未移动。仅在 
graphicsLayer 中应用位置平移后
要解决此问题,您可以通过应用 

one

graphicsLayer 修饰符

before
pointerInput(仅平移位置)和
another
graphicsLayer 修饰符
after
pointerInput 来引入单独的位置平移和旋转进行旋转。为了简化,您应该使用现有的修饰符
offset
rotation
而不是
graphicsLayer
当您将蓝色框的修改器链更改为此时,一切都应该按预期工作:

modifier = Modifier .offset { position.round() } .pointerInput(Unit) { detectDragGestures( onDrag = { change, dragAmount -> change.consume() position += dragAmount } ) } .rotate(rotation) .background(Color.Blue) .size(boxSize)

	
© www.soinside.com 2019 - 2024. All rights reserved.