bounty将于明天到期。回答此问题可获得+500的声望奖励。adammenges正在寻找标准答案。
我有一个应用程序,它有一个父视图(graphView
,带有一个蓝色的粗边框)和一个子视图(nodeView
,绿色框)。每个视图都有自己的SwiftUI DragGesture处理程序。我希望能够用不同的手指移动绿色节点和蓝色边框的图形。
目标:当我主动拖动“蓝边图形”时,保持“绿色节点”在我的手指下。
问题:绿色节点“幽灵”,即似乎在位置周围反弹。
注意事项:
- nodeView上的
.simultaneousGesture
可以让我用一个手指同时拖动图形和节点。但我想用两个手指分别拖动图形和节点:一个在节点上,另一个在图形上。
1.一些UI(例如ZStack
上的.offset
)设置为模仿我的应用程序的实际设置。
如果有更好的方法的话,我也愿意在UIKit中这样做。我怀疑目前的问题是来自图形和节点手势处理程序上的竞争“触发周期”。
struct StackOverflowTestView: View {
@State var graphOffset: CGFloat = .zero
@State var graphPreviousOffset: CGFloat = .zero
@State var nodePosition: CGFloat = 200.0
@State var nodePreviousPosition: CGFloat = 200.0
@State var nodeIsDragged = false
@State var lastNodeTranslation: CGFloat = .zero
var graphDrag: some Gesture {
DragGesture()
.onChanged { graphDragValue in
graphOffset = graphPreviousOffset + graphDragValue.translation.height
// If we're simultaneously dragging the node,
// add inverse graph translation to node's position,
// so that node stays under our finger:
if nodeIsDragged {
nodePosition = nodePreviousPosition + lastNodeTranslation - graphDragValue.translation.height
}
}
.onEnded { _ in
graphPreviousOffset = graphOffset
}
}
var nodeDrag: some Gesture {
// .local: node translation is relative to graph's translation,
// e.g. graph +200, node -200 = node translation is -400
// .global: node translation affected by graph's translation
DragGesture(coordinateSpace: SwiftUI.CoordinateSpace.global)
.onChanged { nodeDragValue in
nodeIsDragged = true
lastNodeTranslation = nodeDragValue.translation.height
nodePosition = nodePreviousPosition + nodeDragValue.translation.height
}
.onEnded { _ in
nodeIsDragged = false
lastNodeTranslation = 0
nodePreviousPosition = nodePosition
}
}
var nodeView: some View {
Rectangle()
.fill(.green.opacity(0.9))
.frame(width: 100, height: 100) // NODE SIZE
.position(x: 500, y: nodePosition) // NODE POSITION
.gesture(nodeDrag)
}
var graphView: some View {
ZStack { nodeView }
.border(.blue, width: 32)
.offset(x: 0, y: graphOffset) // GRAPH OFFSET
.background(Rectangle()
.fill(.pink.opacity(0.1))
.frame(width: 1200, height: 800)
.gesture(graphDrag))
}
var body: some View {
graphView.border(.yellow)
}
}
1条答案
按热度按时间huwehgph1#
你需要在
nodeDrag
-〉DragGesture
-〉.onChanged
内添加反向图形平移到节点的位置。你只在graphDrag
内添加。将
nodeDrag
-〉DragGesture
-〉.onChanged
-〉nodePosition = nodePreviousPosition + nodeDragValue.translation.height
更改为nodePosition = nodePreviousPosition + nodeDragValue.translation.height - (graphOffset - graphPreviousOffset)
FYI -〉我重新排列了下面的等式,得到了
graphDragValue.translation.height
(graphOffset = graphPreviousOffset + graphDragValue.translation.height
)的值。如果你愿意,你可以使用一个单独的状态变量。幽灵行为的解释
这就是你的代码所发生的事情。
当你移动graphView时,在
graphDrag
-〉.onChanged
中,你添加了反向图形平移到节点的位置。这是绝对正确的。所以这使你的nodeView保持在正确的(相同的)位置。但是如果你的手指在nodeView(绿色视图)上稍微改变了
nodeDrag
-〉.onChange
方法get调用。在里面你设置了nodePosition
一个新的值。这里你忘记了你的graphView
已经移动了。所以如果graphView没有移动,nodeView会移动到它应该在的位置。通过
grapDrag
-〉onChanged
,节点视图将移动到正确的位置。因此,这种情况不断发生,nodeView不断在各个位置反弹,这就产生了ghost行为。
如果您将手指保持在nodeView上非常静止(以便不进行onChange get调用),您的代码将工作。
按照我上面提到的那样修改代码就可以解决这个问题。