【问题标题】:SwiftUI: Path's coordinateSpaceSwiftUI:路径的坐标空间
【发布时间】:2019-11-22 17:12:09
【问题描述】:

所以我有以下代码:

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 的坐标空间是相对于灰色框(ContentView)而不是全球的。 Path 在文档中有一个 coordinateSpace 属性,但是关于如何使用它的信息很少,并且使用 SwiftUI 搜索该术语实际上会返回三个结果,所有这些实际上只是指向 Apple 当前稀疏文档的链接。任何人都知道如何最好地解决这个问题?

【问题讨论】:

    标签: ios swift ipad ios-simulator swiftui


    【解决方案1】:

    坐标空间有三种形式:.local、.global 和 .named。前两个很明显。第三个,命名坐标空间,在像你这样的情况下非常有用。它们还可以与 GeometryReader 结合使用。更多详情,请查看https://swiftui-lab.com/geometryreader-to-the-rescue/

    命名坐标空间让您可以在另一个视图的坐标空间中表达一个视图的坐标。为此,SwiftUI 允许您为视图的坐标空间指定名称。然后,在您的代码的其他地方,您可以对其进行引用。在您的示例中,命名 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)
        }
    }
    

    【讨论】:

    • 谢谢!作为旁注,以编程方式判断边缘是否“掉落”在一个圆圈或另一个圆圈上的最佳方法是什么?也许不比较绘制的位置,因为至少可以说这看起来很乱。
    • 不客气。 SwiftUI 似乎支持 DragAndDrop,但仅适用于 macOS (developer.apple.com/documentation/swiftui/dropoperation)。我希望他们最终会将其扩展到 iOS。越早越好。
    • 我更新了代码。我虽然在 ZStack 中有一个错误,但它正在做正确的事情。我错过了几个对齐参数。有关更改的详细信息,您可以查看帖子的编辑差异。
    • 无赖,是的,希望他们尽快将其添加到 iOS。如果需要有两个命名的坐标空间,请稍微扩展一下,它似乎基于圆圈大小和左上角,与我所期望的不太一样:Gif:imgur.com/a/R0E0p5h -- 代码:gist.github.com/adammenges/c83f357888377c2ad3fa6494090dddd0
    • 除了 .coordinateSpace() 之外,您还可以从使用锚首选项(Anchor 和 Anchor)中获益。它们是不透明的类型,将几何图形和坐标空间结合在一起。您使用 GeometryProxy 下标函数来“解码”它们。这是一个广泛的话题,但我已经写了一篇关于它的整篇文章。这是链接:swiftui-lab.com/communicating-with-the-view-tree-part-1
    猜你喜欢
    • 2019-10-19
    • 1970-01-01
    • 2011-01-14
    • 2019-01-07
    • 1970-01-01
    • 2017-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多