如何从 SwiftUI 中的形状创建 NavigationLink 或 Button,仅通过点击形状而不是其框架来触发

How to create a NavigationLink or Button from a shape in SwiftUI that is only triggered by tapping on the shape but not its frame

我有一个简单的形状,我想用作按钮,但我希​​望 link/button 仅在单击形状本身而不是其框架时触发。使用以下代码,在三角形框架内单击时也会触发 link:

struct Triangle: Shape {
    func path(in rect: CGRect)-> Path {
        var path = Path()

        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.minY))

        return path
    }
}
struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(
                destination: Text("DetailView")){
                Triangle()
                    .fill(Color.green)
                    .frame(width: 200, height: 200, alignment: .center)
            }.navigationBarTitle(Text("Triangle"))
        }
    }
}

如何调整代码以仅点击三角形而不点击框架触发 link?

您可以添加一个 contentShape 修饰符来告诉系统如何对 NavigationLink 进行命中测试:

NavigationLink(destination: Text("DetailView")){
    Triangle()
        .fill(Color.green)
        .frame(width: 100, height: 100, alignment: .center)
}
.contentShape(Triangle())

这里有一个警告,即 SwiftUI 在命中测试中包含一些斜率,因此这仍然会接受一些 clicks/touches 接近 边界的 形状,但仍在外面。我没有一个很好的解决方案来摆脱那个污点。但是,您可以看到同样的事情发生在通常构成导航视图的基本 Rectangle 上——例如在它周围放一个 border 并注意你仍然可以在该边界之外轻轻点击。

您可以尝试的第二种方法是单独渲染 Path,将 onTapGesture 附加到它,然后将 on/off 转换为连接到 NavigationLink 的布尔值然后你想移动到你的层次结构之外。类似于:

struct ContentView: View {
    @State var navigationLinkActive = false
    
    var body: some View {
        NavigationView {
            Group {
                if navigationLinkActive {
                    NavigationLink(destination: Text("Detail"), isActive: $navigationLinkActive) {
                        EmptyView()
                    }
                }
                Triangle()
                    .fill(Color.green)
                    .frame(width: 100, height: 100, alignment: .center)
                    .onTapGesture {
                        navigationLinkActive = true
                    }
            }.navigationBarTitle(Text("Triangle"))
            
            
            EmptyView()
            
        }
    }
}

请注意,在此解决方案中,您仍然存在命中溢出问题,加上您失去了触感 down/up 突出显示 Button 具有。