如何在 Jetpack Compose Desktop 中实现鼠标滚轮缩放?

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

我有一个桌面应用程序,我想在其中实现缩放和平移行为,就像这个问题中一样,但没有滚动条。但是,我不知道如何允许用户在精确的点上进行滚轮缩放。我正在使用 Kotlin Compose Multiplatform 1.4.3

平移工作正常,但缩放后偏移计算不正确。缩放后鼠标光标应保持在相同位置。

这是我的代码:

fun main() = singleWindowApplication {
    Surface {
        Box {
            PanAndZoom(
                modifier = Modifier
                    .fillMaxSize()
            ) {
                Box(modifier = Modifier.size(300.dp).background(Color.Gray))
            }
        }
    }
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun PanAndZoom(
    modifier: Modifier = Modifier,
    state: PanAndZoomState = remember { PanAndZoomState() },
    content: @Composable BoxScope.() -> Unit
) {
    Box(
        modifier = modifier
            .onPointerEvent(PointerEventType.Scroll) {
                val change = it.changes.first()
                val delta = change.scrollDelta.y.toInt().sign
                val position = change.position

                val posBeforeZoom = state.screenToWorld(position)

                // Zooming
                state.scale(delta)

                val posAfterZoom = state.screenToWorld(position)
                
                // Incorrect offset calculation
                state.offset += (posBeforeZoom - posAfterZoom)
            }
            .pointerInput(Unit) {
                // Panning
                detectDragGestures { _, dragAmount ->
                    state.offset += dragAmount
                }
            }
            .onGloballyPositioned {
                state.size = it.size
            }
    ) {
        Box(
            modifier = Modifier
                .matchParentSize()
                .graphicsLayer {
                    with(state) {
                        // Applying transformations
                        scaleX = scale
                        scaleY = scale
                        translationX = offset.x
                        translationY = offset.y
                    }
                },
            contentAlignment = Alignment.Center,
            content = content
        )
    }
}

class PanAndZoomState {

    var size: IntSize = IntSize.Zero
    var offset by mutableStateOf(Offset.Zero)
    var scale by mutableStateOf(1f)

    fun scale(delta: Int) {
        scale = (scale * exp(delta * 0.2f)).coerceIn(0.25f, 1.75f)
    }

    fun screenToWorld(screenOffset: Offset): Offset {
        return (screenOffset * scale) + ((size.toOffset() * (1 - scale) ) / 2f)
    }

}

fun IntSize.toOffset(): Offset {
    return Offset(
        x = width.toFloat(),
        y = height.toFloat()
    )
}
kotlin zooming viewport compose-desktop
1个回答
0
投票

不确定是否可以在 Kotlin Compose Multiplatform 1.4.3 中使用可转换,但可以在 1.5.10 中使用。我认为类似的东西可以工作:

var scale by remember { mutableStateOf(1f) }
var rotation by remember { mutableStateOf(0f) }
var offset by remember { mutableStateOf(Offset.Zero) }
val state = rememberTransformableState {
        zoomChange, offsetChange, rotationChange ->
    scale *= zoomChange
    rotation += rotationChange
    offset += offsetChange
}

fun scale(delta: Int) {
    scale = (scale * exp(delta * 0.2f)).coerceIn(0.25f, 1.75f)
}


  Box(
    modifier = modifier
        .graphicsLayer(
            scaleX = scale,
            scaleY = scale,
            rotationZ = rotation,
            translationX = offset.x,
            translationY = offset.y
        )
        .transformable(state = state)
        .fillMaxSize()
        .focusable()
        .onPointerEvent(PointerEventType.Scroll) {
            val change = it.changes.first()
            val delta = change.scrollDelta.y.toInt().sign
            scale(delta)
        } ...
© www.soinside.com 2019 - 2024. All rights reserved.