'Why doesn't SwiftUI onTapGesture always work
The onTapGesture in SWiftUI doesn't work reliably. This example shows the problem, which is that sometimes when you tap on a cell, the background changes to grey as it should, and another time an adjacent cell changes and at other time nothing happens at all. Any ideas why?
struct ContentView: View {
@State var cellFg: [[Color]] = [
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear],
[.clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear, .clear]
]
var body: some View {
VStack {
Spacer()
ForEach(0..<9) { row in
HStack {
Spacer()
ForEach(0..<9) { column in
Rectangle()
.foregroundColor(cellFg[row][column])
.border(Color.gray, width: 1)
// When you tap, it sometimes works, sometimes selects
// an adjacent cell and sometimes does nothing
.onTapGesture {
print("Row \(row) - Column\(column)")
cellFg[row][column] = .gray
}
}
Spacer()
}
}
Spacer()
}
}
}
Solution 1:[1]
Rectangle here is transparent but gesture requires content to be opaque.
Here is a fix (tested with Xcode 11.4 / iOS 13.4)
Rectangle()
.foregroundColor(self.cellFg[row][column])
.border(Color.gray, width: 1)
.contentShape(Rectangle()) // << here !!
the .contentShape
make hit-testable entire frame independently of transparency.
Solution 2:[2]
Add an extension to fix this problem
private struct ExpandAreaTap: ViewModifier {
func body(content: Content) -> some View {
ZStack {
Rectangle()
.foregroundColor(Color.white)
.contentShape(Rectangle())
content
}
}
}
extension View {
func expandTap(tap: @escaping () -> ()) -> some View {
self.modifier(ExpandAreaTap()).onTapGesture(perform: tap)
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Tema Tian |