如何从 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
具有。
我有一个简单的形状,我想用作按钮,但我希望 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
具有。