Reputation: 4884
I'm trying to use NavigationLink
inside List
. For a specific reason, it is in .background
with EmptyView()
.
var body: some View {
List {
Section {
HStack {
Image(systemName: "checkmark")
.frame(width: 30, height: 30, alignment: .center)
.opacity(selected ? 1 : 0)
Text("TEST")
Spacer()
}
.onTapGesture {
selected.toggle()
}
.background(
NavigationLink(destination: WifiView()) { EmptyView() }
.disabled(isPad)
)
}
}
}
The problem is the touch area for the NavigationLink
is not as expected.
.background
's area is as above.
but NavigationLink
and EmptyView
's area is as above. I tried to force the frame with .frame
but it won't change.
What am I missing?
Upvotes: 1
Views: 1137
Reputation: 13980
To distill the accepted answer: all you need to do is to add .contentShape(Rectangle())
to the same element which has .onTapGesture
. This solution works for any container, not just List
.
E.g. if you have:
VStack {
// ...
}
.onTapGesture {
// ...
}
Add contentShape
to the same element:
VStack {
// ...
}
.contentShape(Rectangle())
.onTapGesture {
// ...
}
Rationale:
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: 2
Reputation: 36368
try something like this, works well for me:
var body: some View {
List {
Section {
HStack {
Image(systemName: "checkmark")
.frame(width: 30, height: 30, alignment: .center)
.opacity(selected ? 1 : 0)
Text("TEST")
Spacer()
}
.contentShape(Rectangle()) // <--- here
.onTapGesture {
selected.toggle()
}
.background(
NavigationLink(destination: WifiView()) { EmptyView() }
.disabled(isPad)
)
}
}
}
Upvotes: 2