我有一个光标图标,我想让它在用户拖动它时保持在用户手指的中心,但是由于触摸误差和其他各种原因,它不能通过 onDrag 中的拖动量简单地更新视图的偏移量来保持中心位置。
我以为我可以计算触摸点的全局 XY 并将其设置为该值,但如果不执行诸如使用 pointerInterop 修饰符之类的令人沮丧的操作,则很难在 Compose 中获取该值。
onDrag = { change, dragAmount ->
change.consume()
params.x += dragAmount.x.toInt()
params.y += dragAmount.y.toInt()
wm.updateViewLayout(composeView, params)
}
更新 1
肯定有一些明显的数学知识我没注意到。我能够通过将视图按偏移量移动,将视图的中心点与用户在 DragStart 上的手指同步,如下所示:
onDragStart = {
params.x = params.x + it.x.toInt() - (composeView.width / 2)
params.y = params.y + it.y.toInt() - (composeView.height / 2)
wm.updateViewLayout(composeView, params)
},
onDrag = { change, dragAmount ->
change.consume()
//cant do that here though so doing the normal way below
// params.x = params.x + change.position.x.toInt() - (composeView.width / 2)
// params.y = params.y + change.position.y.toInt() - (composeView.height / 2)
params.x += dragAmount.x.toInt()
params.y += dragAmount.y.toInt()
wm.updateViewLayout(composeView, params)
}
如果我注释掉 dragamount 增量方式并使用调整后的方式,拖动它时它会变得不稳定,疯狂地跳来跳去。
我尝试了一些其他技术,例如使用awaitEachGesture
(如下所示)drag
来摆脱触摸倾斜检测,但这并没有让我更接近目标。
真正的问题似乎发生在用户拖动速度非常慢的时候。如果你拖动得非常慢,出于某种原因,你的手指就会从视图中移开。这就像视图对非常微小的移动没有反应一样。
我想要做的就是让视图保持在触摸点的中心。这似乎应该只是一些具有现有可用参数的公式。
.pointerInput(Unit) {
awaitEachGesture {
val down = awaitFirstDown()
drag(down.id) { change ->
val posChange = change.positionChange()
val pos = change.position
Log.i("await gesture drag", "change: ${pos}")
Log.i("await gesture drag", "poschange: ${posChange}")
change.consume()
params.x += posChange.x.toInt()
params.y += posChange.y.toInt()
// params.x = params.x + pos.x.toInt() - (composeView.width / 2)
// params.y = params.y + pos.y.toInt() - (composeView.height / 2)
wm.updateViewLayout(composeView, params)
}
}
}
我还制作了此 GIF 来展示问题。首先,您可以看到,即使我移动得很快,触摸点也会有一些漂移。它会移到圆圈的边缘。更糟糕的是,如果我移动得非常慢,它会漂移很多。
更新 2
我刚刚意识到这可能是因为布局参数 x 和 y 的拖动量必须四舍五入为整数。我明天会调查一下。
更新 3
我关于舍入的理论是正确的。当您非常缓慢地拖动时,更改位置/拖动量浮点.toInt()
会向下舍入为零,并且不会造成任何移动。将其更改为roundToInt
也不起作用,因为缓慢的移动会在向上舍入时慢慢爬过您的手指。对我来说,解决方案是使用浮点累加器,这样小的拖动量就不会被吞没。我猜这是因为我围绕父 ComposeView 移动,而不是从触摸元素自己的.offset
修饰符移动?我不太确定有什么区别,因为我知道您不需要通常的拖动技术累加器,也许引擎盖下有一个隐藏的累加器?
.pointerInput(Unit) {
val center = size.center
awaitEachGesture {
val down = awaitFirstDown()
params.x += (down.position.x - center.x).roundToInt()
params.y += (down.position.y - center.y).roundToInt()
wm.updateViewLayout(composeView, params)
drag(down.id) { change ->
val posChange = change.positionChange()
change.consume()
accumulatedX += posChange.x
accumulatedY += posChange.y
val deltaX = accumulatedX.toInt()
val deltaY = accumulatedY.toInt()
accumulatedX -= deltaX
accumulatedY -= deltaY
params.x += deltaX
params.y += deltaY
wm.updateViewLayout(composeView, params)
}
}
}