如何使某些点能够像视频中那样通过一组视图边缘进行拖动:
而不是自由拖拽:
我甚至不知道从哪里开始,因为没有 GeometryReader 我就无法测量视图的边界。
然而,GeometryReader 在这种情况下并不合适,因为这些是位于不同图层上的不同视图。
示例视图:
struct ContentView: View {
@State var point: CGPoint = .zero
var body: some View {
ZStack {
//foreach Nodes
NodeView()
NodeView()
.offset(x:0, y:100)
//foreach Points
BezierPoint(p1: $point)
}
}
}
struct NodeView : View {
// var nodeViewModel: NodeViewModel
// with exact location in space
var body: some View {
Text("Business")
.multilineTextAlignment(.center)
.foregroundStyle(.red)
.shadow(color: .black, radius: 2 )
.frame(minHeight: 40)
.padding( EdgeInsets(horizontal: 20, vertical: 14) )
.background {
// ANY Shape can be here
RoundedRectangle(cornerRadius: 10)
}
}
}
struct BezierPoint: View {
@Binding var p1: CGPoint
let pointsSize: CGFloat = 15
var body: some View {
GeometryReader { reader in
ControlPointHandle(size: pointsSize)
.offset( CGSize(width: p1.x + reader.size.width/2, height: p1.y + reader.size.height/2) )
.gesture(
DragGesture()
.onChanged { value in
self.p1 = value.location.relativeToCenter(of: reader.size, minus: true)
}
)
}
}
}
private struct ControlPointHandle: View {
let size: CGFloat
var body: some View {
Circle()
.frame(width: size, height: size)
.overlay(
Circle()
.stroke(Color.blue, lineWidth: 2)
)
.offset(x: -size/2, y: -size/2)
}
}
fileprivate extension CGPoint {
func relativeToCenter(of size: CGSize, minus: Bool = false) -> CGPoint {
let a: CGFloat = minus ? -1 : 1
return CGPoint(x: x + a * size.width/2, y: y + a * size.height/2)
}
}
是否可以检测当前哪个视图位于 DragGesture 的位置下?答案中显示的技术可用于检测形状何时位于拖动点下(这是我的答案)。这
GeometryReader
在形状的背景中使用了,即使您有多层视图,它也应该有效。为了找到形状边缘上最接近拖动点的点,我建议采用以下方法:
Path
函数lineIntersection(_:eoFill:)
查找线与形状的交点。您之前使用 包裹每个点
GeometryReader
。AGeometryReader
很贪婪,会占用所有可用空间,因此这会使每个点的大小膨胀到父视图的完整大小。我建议不要这样做,而是使用.onGeometryChange
来测量每个点的位置。以下是更新后的示例,以显示其工作原理。它包括第二个点,因此也可以测试这些点的独立性。