Reputation: 8707
my tapAction
is not recognizing a tap when my foregroundColor
is clear
. When i remove the color it works fine.
That's my code:
ZStack {
RoundedRectangle(cornerRadius: 0)
.foregroundColor(Color.clear)
.frame(width: showMenu ? UIScreen.main.bounds.width : 0)
.tapAction {
self.showMenu.toggle()
}
RoundedRectangle(cornerRadius: 5)
.foregroundColor(Color.green)
.shadow(radius: 5, y: 2)
.padding(.trailing, 50)
.frame(width: showMenu ? UIScreen.main.bounds.width : 0)
}
.edgesIgnoringSafeArea(.top)
Upvotes: 51
Views: 15827
Reputation: 385590
51N4’s answer is better and you should do that.
I have also discovered that a shape filled with Color.clear
does not generate a tappable area.
Here are two workarounds:
Use Color.black.opacity(0.0001)
(even on 10-bits-per-channel displays). This generates a color that is so transparent that it should have no effect on your appearance, and generates a tappable area that fills its frame. I don't know if SwiftUI is smart enough to skip rendering the color, so I don't know if it has any performance impact.
Use a GeometryReader
to get the frame size, and then use the contentShape
to generate the tappable area:
GeometryReader { proxy in
Color.clear.contentShape(Path(CGRect(origin: .zero, size: proxy.size)))
}
Upvotes: 29
Reputation: 490
In my case a View that didn't trigger onTapGesture:
struct MainView: View {
var action: () -> Void
var body: some View {
NotTappableView()
.contentShape(Rectangle())
.onTapGesture(
action()
)
}
}
I solved this way:
struct MainView: View {
var action: () -> Void
var body: some View {
NotTappableView()
.overlay(
Color.clear
.contentShape(Rectangle())
.onTapGesture {
action()
}
)
}
}
This made whole untappable view now tappable.
Upvotes: 2
Reputation: 2147
Here is the component
struct InvisibleButton: View {
let action: (() -> Void)?
var body: some View {
Color.clear
.contentShape(Rectangle())
.onTapGesture {
action?()
}
}
}
usage: Put your view and InbisibleButton in ZStack
ZStack {
**yourView()**
InvisibleButton {
print("Invisible button tapped")
}
}
you also can make a modifier to simplify usage:
struct InvisibleButtonModifier: ViewModifier {
let action: (() -> Void)?
func body(content: Content) -> some View {
ZStack {
content
InvisibleButton(action: action)
}
}
}
**yourView()**
.modifier(InvisibleButtonModifier {
print("Invisible button tapped")
})
However, if your SwiftUI View has a UIKit view as a subview under, you will have to set Color.gray.opacity(0.0001) in order to UIView's touches be ignored
Upvotes: 15
Reputation: 844
The accurate way is to use .contentShape(Rectangle())
on the view.
Described in this tutorial:
control-the-tappable-area-of-a-view by Paul Hudson @twostraws
VStack {
Image("Some Image").resizable().frame(width: 50, height: 50)
Spacer().frame(height: 50)
Text("Some Text")
}
.contentShape(Rectangle())
.onTapGesture {
print("Do Something")
}
how-to-control-the-tappable-area-of-a-view-using-contentshape stackoverflow
Upvotes: 82