I had the same problem with one of my apps. I didn;t find a 'clean' way to do it, but managed to get it working as follows:
struct Test: View {
@State private var selection: String?
let names = [
"Cyril",
"Lana",
"Mallory",
"Sterling"
]
var body: some View {
NavigationStack {
List(names, id: \.self) { name in
Text(name)
.frame(maxWidth: .infinity, alignment: .leading)
.contentShape(Rectangle())
.listRowBackground(selection == name
? Color.green.opacity(0.3)
: Color.clear)
.onTapGesture {
selection = name
}
}
.navigationTitle("List Selection")
}
}
}
Firstly, you have to handle setting the selected item yourself. So the selection is now set in the onTapGesture. This stops the list handling the tap. However, it introduces another problem in that the tap only works if you tap on the text.
To fix that, I added a frame, setting the maxWidth to the full width of the list (.infinity). and setting the alignment to leading. If you don't set the alignment, it will center the content. To make the entire row tappable, I then added the contentShape.
Once this is in place, I used the listRowBackground to set the colour I wanted for the selected row or to set the background to clear for those rows not selected.
It's a bit of extra work, but it gets the desired effect and has the side benefit of being able to fire off any otyher processes you need to when an item is selected.
Steve