Consider this simple CardView in SwiftUI:
struct CardView: View {
let cardNumber: Int
var body: some View {
VStack {
Image("bg1")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(height: 100)
.clipped()
Spacer()
Text("Card: \(cardNumber.description)")
.font(.title.bold())
Button("Test") { print("Tapped") }
.buttonStyle(.bordered)
}
.background(.green)
.frame(height: 260)
.border(.blue)
}
}
The VStack
is set to height 260 and the Image
is set to height 100 and with the content model .fill
. I understand that we need to set .clipped()
to prevent the image from extend beyond the view's bounds.
If I render this view alone, everything works fine i.e. tap the button and print "Tapped".
However, if I'd render multiple CardView
, for example put this CardView
inside a VStack
or ScrollView
. The clipped image will start overlapping and the Test button will no-longer work.
From the UI debugger I can see it render as below inside the VStack
.
Could someone please explain why this is happening and how to fix it?
I realized that .clipped
family will not prevent the Image itself from tap action, you need to add .contentShape
, which makes the Image not overwhelm the surrounding context:
Image("bg1")
...
.contentShape(Rectangle()) //<- here