I have a SwiftUI view where I display a background image with a mockup of an iPhone over it. The mockup has a transparent area to show the background image. I want to add a Color.black.opacity(0.2) overlay to darken the background image for better readability of the content. However, I want the dark overlay to exclude the transparent area of the mockup.
I tried the following approach:
Color.black.opacity(0.2)
.ignoresSafeArea()
.overlay(
Image(.mockup)
.resizable()
.scaledToFit()
.blendMode(.destinationOut)
)
This approach doesn’t seem to work as expected—the dark overlay is still visible over the mockup’s transparent area.
Here’s the full code for context:
import SwiftUI
struct ContentView: View {
@State var name: String = ""
var body: some View {
ZStack {
Image(.cover)
.resizable()
.scaledToFill()
.ignoresSafeArea()
VStack {
Image(.mockup)
Spacer()
Text("Lucas & Lavínia")
.font(.title)
.fontWeight(.bold)
Spacer().frame(height: 24)
TextField(
"",
text: $name,
prompt: Text("Nome").foreground(.white)
)
.padding(15)
.background(.white.opacity(0))
.overlay(
RoundedRectangle(
cornerRadius: 8
)
.stroke(
.white,
lineWidth: 1
)
)
.clipShape(.rect(cornerRadius: 8))
.foregroundStyle(.white)
Spacer().frame(height: 24)
Button {
} label: {
HStack {
Text("Selecionar fotos da galeria")
}
.frame(maxWidth: .infinity)
.foregroundColor(.white)
.padding(.vertical, 15)
.background(.red)
.cornerRadius(40)
}
.frame(maxWidth: .infinity)
Spacer().frame(height: 24)
Button {
} label: {
Text("Capturar foto agora")
}
Spacer().frame(height: 35)
}
.frame(maxWidth: .infinity)
.foregroundStyle(.white)
.padding(.all)
.padding(.top, 25)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
}
}
#Preview {
ContentView()
}
How can I apply the black overlay only to the parts of the background image that are not covered by the mockup? Is there a way to mask or exclude the area inside the transparent section of the mockup? Or would I need a completely different approach to achieve this effect?
Any guidance or code examples would be greatly appreciated!
2
Answers
The code adds a dark overlay to the background image but keeps the mockup’s transparent area clear. Here’s how:
This keeps the mockup clear while making the rest of the background darker for better readability. Just ensure the mockup image is a transparent PNG!
You can replace rectangle ("// Exclude mockup area") with your image. Try below code:
First of all, I would suggest showing the base image in the background of the
ZStack
, instead of as the first layer of theZStack
. This way, the overflow from scaling-to-fill will not cause theZStack
to extend off-screen.Then, a masking layer can be added as the first layer of the
ZStack
, which is seen above the background image.The mask is formed using semi-transparent
Color.black
.A
RoundedRectangle
is overlayed over the semi-transparent background. The corner radius should approximately match the shape of the mockup.The rounded rectangle is applied using
.blendMode(.destinationOut)
. This causes the shape to be cut out from the underlying semi-transparent black layer.The modifier
.compositingGroup()
is applied, to prevent blend mode from burning deeper into lower layers.To match the size and position of the cut-out with the mockup image in the
VStack
,.matchedGeometryEffect
can be used. This requires a namespace:Here is the example with updates applied: