You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose自定义Composable双指围绕捏合中心缩放时逆变换异常的问题求助

Jetpack Compose自定义Composable双指围绕捏合中心缩放时逆变换异常的问题求助

我现在在Jetpack Compose里基于Composable做一个自定义视图,想实现双指缩放和平移功能——而且因为已经有很多自定义拖拽手势了,没法直接用内置的手势检测器。目前我想实现围绕双指捏合的中心(质心)来缩放,如果固定以左上角(0,0)为原点缩放是正常的,但换成围绕捏合中心缩放时,inverseTransform函数的结果总是比实际触摸位置偏左,这直接搞崩了我其他的拖拽功能。

我的手势逻辑写在pointerInput的awaitPointerEventScope里,系统会不断回调更新手指位置:

// 双指手势:缩放、平移及合并
.pointerInput(Unit) {
    awaitPointerEventScope {
        // 手势检测逻辑写在这里
    }
}

当检测到开始缩放时,我会先保存双指的中点作为缩放支点,pivotPoint、panOffset和scale都是用remember声明的状态变量:

// 开始缩放
if(!isZooming){
    // 计算双指的中点作为缩放支点
    pivotPoint = (pointer1.position + pointer2.position) / 2f
    pivotPoint = inverseTransform(pivotPoint)
}
isZooming = true
Log.d("zoom", "zooming")

// 计算前后双指距离的变化
val previousDistance = (pointer1History[sampleSize - 2] - pointer2History[sampleSize - 2]).getDistance()
val currentDistance = (pointer1History.last() - pointer2History.last()).getDistance()

// 计算缩放比例的变化量
val zoomChange = currentDistance / previousDistance
val newScale = (scale * zoomChange).coerceIn(minScale, maxScale)
val scaleFactor = newScale / scale

// 我尝试过好几种panOffset的计算方式(代码里注释掉的是之前试的)
// panOffset = Offset(zoomChange * panOffset.x +pivotPoint.x, zoomChange * panOffset.y + pivotPoint.y)
// panOffset = (panOffset - pivotPoint) * scaleFactor + pivotPoint
// panOffset = panOffset + (pivotPoint - panOffset) * (1 - scaleFactor)

// 目前在用的panOffset计算逻辑
panOffset += Offset(
    (1 - scaleFactor) * (pivotPoint.x - panOffset.x),
    (1 - scaleFactor) * (pivotPoint.y - panOffset.y)
)

Log.d("zoom", "panoffset: $panOffset")

// 更新最终的缩放比例
scale = newScale

绘制时我用withTransform来应用缩放和平移:

withTransform({
    // 我试过不同的变换组合(注释掉的是之前尝试的步骤)
    // translate(pivotPoint.x, pivotPoint.y)
    // scale(scale,scale, pivotPoint)
    // translate(-pivotPoint.x, -pivotPoint.y)
    // translate(panOffset.x, panOffset.y)

    scale(scale, scale, pivotPoint)
}) {
    // 这里绘制自定义内容
}

最后是用来把触摸点转换到未缩放平移坐标系的逆变换函数:

fun inverseTransform(touchPoint: Offset): Offset {
    return (touchPoint - panOffset) / scale
}

现在的核心问题是,inverseTransform转换后的触摸点总是比实际位置偏左,导致所有依赖触摸坐标的拖拽功能全部错位。我试过调整panOffset的计算方式,但都没解决这个偏移问题,有没有人能帮我看看哪里错了?


备注:内容来源于stack exchange,提问作者confused

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:14:32