SwiftUI:路径的坐标空间

SwiftUI: Path's coordinateSpace

所以我得到了以下代码:

import SwiftUI

struct ContentView : View {
    @State private var draggingLocation = CGPoint.zero
    @State private var startLocation = CGPoint.zero
    @State private var dragging = false

    var body: some View {
        let GR = DragGesture(minimumDistance: 10, coordinateSpace: .global)
            .onEnded { value in
                self.dragging = false
                self.draggingLocation = CGPoint.zero
                self.startLocation = CGPoint.zero
            }
            .onChanged { value in
                if !self.dragging {
                    self.dragging = true
                }
                if self.startLocation == CGPoint.zero {
                    self.startLocation = value.startLocation
                }
                self.draggingLocation = value.location
            }

        return ZStack {
            if self.dragging {
                Path { path in
                    path.move(to: CGPoint(x: self.startLocation.x-5, y: self.startLocation.y-5))
                    path.addLine(to: CGPoint(x: self.draggingLocation.x-5, y: self.draggingLocation.y+5))
                    path.addLine(to: CGPoint(x: self.draggingLocation.x+5, y: self.draggingLocation.y-5))
                    path.addLine(to: CGPoint(x: self.startLocation.x+5, y: self.startLocation.y+5))
                }
                .fill(Color.black)
            }

            Circle()
            .fill(self.dragging ? Color.blue : Color.red)
            .frame(width: 100, height: 100)
            .gesture(GR)
            .offset(
                x: 75,
                y: 75
            )

            Circle()
            .fill(self.dragging ? Color.blue : Color.red)
            .frame(width: 100, height: 100)
            .gesture(GR)
            .offset(
                x: -75,
                y: -75
            )
        }
        .frame(width: 400, height: 400)
        .background(Color.gray)
    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

导致此行为的结果:

我希望能够将边缘从一个圆拖出并拖入另一个圆,问题当然是 Path 的坐标 space 是相对于灰色的box (ContentView) 而不是全局的。 A Path 在文档中有一个 属性 coordinateSpace 但是关于如何使用它的信息很少,用 SwiftUI 搜索这个术语字面上 returns 三个结果,所有这些都是实际上只是指向 Apple 当前稀疏文档的链接。任何人都知道如何最好地解决这个问题?

坐标 space 有三种形式:.local、.global 和 .named。前两个很明显。第三个,named coordinate spaces,在像你这样的情况下非常有用。它们也可与 GeometryReader 结合使用。有关详细信息,请查看 https://swiftui-lab.com/geometryreader-to-the-rescue/

命名坐标 spaces 让您可以在另一个视图的坐标 space 中表达一个视图的坐标。为此,SwiftUI 允许您为视图的坐标 space 指定名称。然后,在您代码的其他地方,您可以引用它。在您的示例中,命名 ZStack 的坐标是可行的方法。

这是重构后的代码:

注意:我移动了下面的路径,只是让它画在圆圈的前面。而且,注意第一个路径,它只是为了防止我认为是 ZStack 中的错误。

import SwiftUI

struct ContentView : View {
    @State private var draggingLocation = CGPoint.zero
    @State private var startLocation = CGPoint.zero
    @State private var dragging = false

    var body: some View {
        let GR = DragGesture(minimumDistance: 10, coordinateSpace: .named("myCoordinateSpace"))
            .onEnded { value in
                self.dragging = false
                self.draggingLocation = CGPoint.zero
                self.startLocation = CGPoint.zero
        }
        .onChanged { value in
            if !self.dragging {
                self.dragging = true
            }

            if self.startLocation == CGPoint.zero {
                self.startLocation = value.startLocation
            }
            self.draggingLocation = value.location
        }

        return ZStack(alignment: .topLeading) {

            Circle()
                .fill(self.dragging ? Color.blue : Color.red)
                .frame(width: 100, height: 100)
                .overlay(Text("Circle 1"))
                .gesture(GR)
                .offset(x: 75, y: 75)

            Circle()
                .fill(self.dragging ? Color.blue : Color.red)
                .frame(width: 100, height: 100)
                .overlay(Text("Circle 2"))
                .gesture(GR)
                .offset(x: 200, y: 200)

            if self.dragging {
                Path { path in
                    path.move(to: CGPoint(x: self.startLocation.x-5, y: self.startLocation.y-5))
                    path.addLine(to: CGPoint(x: self.draggingLocation.x-5, y: self.draggingLocation.y+5))
                    path.addLine(to: CGPoint(x: self.draggingLocation.x+5, y: self.draggingLocation.y-5))
                    path.addLine(to: CGPoint(x: self.startLocation.x+5, y: self.startLocation.y+5))
                }
                .fill(Color.black)
            }

        }
        .coordinateSpace(name: "myCoordinateSpace")
        .frame(width: 400, height: 400, alignment: .topLeading)
        .background(Color.gray)
    }
}