After spending a whole day on this, I found a way that seems to be working on iOS 14 by wrapping a NavigationLink inside a button's label and triggering it programmatically using the button's action. The highlight color seems to be clearing right after the tap (because it's a button that is being tapped, not the NavigationLink).
The trick is that the NavigationLink uses an EmptyView() as it's content, so it's there to define the navigation but not to trigger it itself and let the button do it programmatically.
I wrote a custom NavLink struct that accepts similar parameters as the NavigationLink and does the wrapping for you:
struct NavLink<Content: View, Destination: View>: View {
var destination: Destination
var tag: String
@Binding var selection: String?
@ViewBuilder var content: Content
var body: some View {
Button(action: {
selection = tag
}, label: {
ZStack {
NavigationLink(destination: destination, tag: tag, selection: $selection) {
EmptyView()
}
.isDetailLink(true)
content
}
})
}
}
Here's how it can be used:
NavLink(destination: Text("Destination"), tag: "tag", selection: $selection) {
Text("List item goes here")
}
(I've included an .isDetailLink
modifier to the NavigationLink, in case you don't need it you can take it away or add a new argument to set it).
Seems to be working well for me, please share your feedback and any potential ways that it can be improved.