Ryan
Ryan

Reputation: 4884

NavigationLink touch area

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 area

.background's area is as above.

NavigationLink and EmptyView area

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

Answers (2)

timbre timbre
timbre timbre

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

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

Related Questions