Reputation: 3194
The problem is to make a NavigationLink
from a Rectangle
which:
Color.clear
foreground color) andbuttonStyle
set to PlainButtonStyle()
or .plain
(to remove the blue text overlay)have hit testing such that gestures in the empty space trigger navigation.
Simple example:
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
// tap gestures anywhere in the rectangle work as expected
NavigationLink(destination: Text("target 1")) {
Rectangle().foregroundColor(.red)
}
.buttonStyle(PlainButtonStyle())
// touch gestures anywhere in the rectangle don't navigate (if this were a ZStack with some Text in the Rectangle, only gestures on the Text would work)
NavigationLink(destination: Text("target 2")) {
Rectangle().stroke(lineWidth: 2)
}
.buttonStyle(.plain)
}
.padding(20)
}
}
}
Preview:
The problem is that gestures inside the second (white or clear) rectangle don't trigger navigation. Removing the buttonStyle(.plain)
is not an option.
Upvotes: 0
Views: 257
Reputation: 3194
The solution is to add a contentShape
modifier to tell the system how to do hit testing for the NavigationLink
:
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("target 2")) {
Rectangle()
.stroke(lineWidth: 2)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
}
.padding(20)
}
}
}
I suspect this has to do with how the hit testing is managed for the PlainButtonStyle
, as alluded to in this answer:
If you add a tap gesture to a container SwiftUI view, such as VStack or HStack, then SwiftUI only adds the gesture to the parts of the container that have something inside – large parts of the stack are likely to be untappable.
If this is what you want then the default behavior is fine. However, if you want to change the shape of hit tests – the area that responds to taps – then you should use the contentShape() modifier with the shape you want.
(source)
Upvotes: 0