【发布时间】:2015-10-18 16:35:00
【问题描述】:
我决定重写这个问题。我试图让它清晰而简短,但没有成功。
我想要实现的是一个可以放在任何东西上的对象(Rectangle、Image 等等)并让它响应触摸手势。不幸的是,我遇到了一个我无法解决的问题。我找不到帮助,所以我在这里尝试。
这里很简单main.qml:
import QtQuick 2.5
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Touch surface test")
width: 640
height: 480
visible: true
Rectangle {
width: 200
height: 60
color: "blue"
MyTouchSurface {
id: myTouchSurface
anchors.fill: parent
}
}
}
这里是 MyTouchSurface.qml
import QtQuick 2.5
MultiPointTouchArea {
id: myTouchSurface
// this is object I want to respond to touch gestures
property Item target: parent
// this is object I want to keep target in. I won't let target get out of it
property Item container: parent.parent
property double targetX: target.x
property double targetY: target.y
property double centerX: target.width / 2
property double centerY: target.height / 2
property double lastTouchX
property double lastTouchY
property double lastXDrag
property double lastYDrag
// here I calculate received touches and move target
onPressed: {
lastTouchX = touchPoints[0].sceneX
lastTouchY = touchPoints[0].sceneY
if (slidingAnimation.running)
slidingAnimation.stop()
}
onTouchUpdated: {
if (touchPoints.length) {
target.x += touchPoints[0].sceneX - lastTouchX
target.y += touchPoints[0].sceneY - lastTouchY
lastXDrag = touchPoints[0].sceneX - lastTouchX
lastYDrag = touchPoints[0].sceneY - lastTouchY
lastTouchX = touchPoints[0].sceneX
lastTouchY = touchPoints[0].sceneY
}
else
startSliding()
}
// when lifting fingers off screen I want to slide target across it's container
function startSliding() {
slidingAnimation.toX = target.x + lastXDrag * 10
slidingAnimation.toY = target.y + lastYDrag * 10
slidingAnimation.restart()
}
// This is animation responsible for sliding the target
ParallelAnimation {
id: slidingAnimation
property double toX
property double toY
property int animationDuration: 250
NumberAnimation {
target: myTouchSurface.target
property: "x"
to: slidingAnimation.toX
duration: slidingAnimation.animationDuration
easing.type: Easing.OutQuad
}
NumberAnimation {
target: myTouchSurface.target
property: "y"
to: slidingAnimation.toY
duration: slidingAnimation.animationDuration
easing.type: Easing.OutQuad
}
}
// this is how I keep target object within container
onTargetXChanged: {
if (container != null) {
if (target.x + centerX < 0)
target.x = -centerX
else if (target.x + centerX > container.width)
target.x = container.width - centerX
}
}
onTargetYChanged: {
if (container != null) {
if (target.y + centerY < 0)
target.y = -centerY
else if (target.y + centerY > container.height)
target.y = container.height - centerY
}
}
}
我希望在MyTouchSurface 中包含所有计算和函数,以便轻松应用于其他对象并在其他项目中使用它。
我的问题是我不知道如何防止目标对象移出容器。好吧,这里的代码运行得很好,但它也会产生关于绑定循环的非常丑陋的错误。
发生了什么:
- 当目标的 x 和 y 发生变化时,我会检查它们
- 如果 x 或 y 超出指定区域,我会将它们移回
- 我再次收到信号“x changed”或“y changed”
- 我收到有关循环的错误,因为我的函数导致自己再次执行
所以我想问:有没有其他简单的方法可以防止对象飞出屏幕并且不会同时收到绑定循环错误?
我知道我可以不时使用Timer 来检查目标的x 和y,并将它们带回来。
我知道我可以更改动画的 easing 和 duration,使其停在容器边界上,但看起来好像已停止。
说真的。没有简单的方法吗?
不起作用的事情:
- 在容器外检测到对象后停止动画(如果它移动得非常快,它将停止在屏幕外)
- 停止动画然后更改目标的
x或y
感谢到目前为止帮助我的所有人。很高兴知道我在这里并不孤单:)
【问题讨论】:
-
忽略警告可能是最糟糕的决定。绑定循环提示您做错了什么,您应该进一步调查 qml 引擎在抱怨什么。您的目标应该是正确设计您的 qml 文件,这意味着:更改基于拖动交互转换项目位置的方式。为了帮助您,我们需要的不仅仅是那几行代码。
-
@qCring 我附上了简单的例子,你可以复制粘贴来重现我的问题。
-
你确实有一个绑定循环。修理它。让我解释一下您的问题:“我知道我有问题,但我不想解决它”。如果是这样,你的问题是什么? (不,警告不能被删除,这是有充分理由的 - QML 正在保护你的脚免受你自己的伤害。)
-
@KubaOber 我就是不明白。算法是这样的:如果变量发生变化,检查它是否保持在想要的范围之间,如果不是 - 改变它。如果操作再次触发,更改它会导致相同的结果。然后出现警告。我该如何解决?那是我的问题。如果它是一个循环,那么很好,无论如何,但我真的没有看到任何简单的方法来改变它。如果我们谈论删除警告 - 请查看示例代码。相同的操作在一个地方会导致错误,而在另一个地方不会。对我来说,一切都不是那么明显。