我有一个应用程序,其中有一个父视图(graphView
,带有粗蓝色边框)和一个子视图(nodeView
,绿色方框)。每个都有自己的SwiftUI DragGesture处理程序。我想能够使用不同的手指移动绿色节点和带有不同手指的蓝色边框图形。
目标:在我主动拖动“蓝色边框图形”的同时,将“绿色节点”保持在我的手指下。
问题:绿色节点“幽灵”,即似乎在位置上反弹。
注意:
.simultaneousGesture
在nodeView上会让我使用单个手指在节点上同时拖动图形和节点。但是我想使用两个单独的手指拖动图形和节点:一个在节点上,另一个在图形上。- 一些UI(例如
ZStack
上的.offset
)设置为模仿我的应用程序的实际设置。
如果有更好的方法,我也可以在UIKit中完成此操作。我怀疑问题当前来自于竞争的'firing cycles'在图形与节点手势处理程序之间。
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)
}
}