SwiftUI - clipping shadow on a view with transparency

Viewed 1438

How can I clip a shadow on a view that has transparent background using SwiftUI?

What I want to achieve is to have the possibility of getting the shadow clipped outside of the RoundedRectangle and not displaying shadow inside of it. (you can see that - "Text" has some black background, which is the shadow)

What I try to achieve: (done this using CSS) - the background inside have transparency enter image description here

My Result:

enter image description here

Text("Text") 
        .multilineTextAlignment(.leading)
        .padding(EdgeInsets(top: 8, leading: 14, bottom: 8, trailing: 14))
        .font(.system(size: 13, weight: .medium, design: .default))
        .overlay(RoundedRectangle(cornerRadius: 10, style: .continuous)
                .fill(Color.init(Color.RGBColorSpace.sRGB, white: 1, opacity: 0.2))
                .shadow(color: Color.black, radius: 6, x: 0, y: 3)).padding(30)
5 Answers

If it is Ok to also have a certain blur effect, you could use a view presenting a UIBlurEffect as the background for the text. You will still get a transparency effect but now with an opaque view that doesn't mess up the shadow.

Code:

ZStack {
    Color.blue
    Text("Hello, World!")
        .padding(7)
        .background(BlurView(style: .systemUltraThinMaterial))
        .clipShape(RoundedRectangle(cornerRadius: 10.0))
        .shadow(color: Color.black.opacity(0.5), radius: 6, x: 0, y: 3)
}

Result:

enter image description here

And BlurView is just a SwifUI wrapper around UIVisualEffectView

struct BlurView: UIViewRepresentable {
    typealias UIViewType = UIVisualEffectView
    
    let style: UIBlurEffect.Style
    
    init(style: UIBlurEffect.Style = .systemMaterial) { self.style = style }
    
    func makeUIView(context: Context) -> UIVisualEffectView {
        return UIVisualEffectView(effect: UIBlurEffect(style: style))
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        uiView.effect = UIBlurEffect(style: style)
    }
}

What worked for me was using an image of the desired shape as the background for the text.

ZStack{
    Text("Begin")
        .background(
            Image("{Image Name}")
                .resizable()
                .opacity(0.1)
                .shadow(color: Color.black, radius: 8, x: -1, y: -1)
        )
}

https://i.stack.imgur.com/y3rka.png

I recently faced this problem while working on a client project. We can place a RoundedRectangle, applied with the shadow and a white fill, along with the desired content's background color within a ZStack.

ZStack {
    RoundedRectangle(cornerRadius: 10, style: .continuous)
        .fill(Color(white: 1, opacity: 1))
        .shadow(color: .black, radius: 6, x: 0, y: 3)
    Color.gray.opacity(0.4)
        .cornerRadius(10)
    Text("Content")
}

The best solution I found, hope it will help someone :)

ZStack {
    RoundedRectangle(cornerRadius: 10)
            .shadow(color: .black.opacity(0.25), radius: 4, x: 0, y: 4)
    RoundedRectangle(cornerRadius: 10)
            .blendMode(.destinationOut)
    RoundedRectangle(cornerRadius: 10, style: .continuous)
            .fill(.green.opacity(0.5))
    Text("Our Fancy Text")
}
.frame(width: 100, height: 50)
.compositingGroup()
struct ContentView: View {
    var body: some View {
        ZStack {
            Color.red.frame(width: 60, height: 30, alignment: .center)
            .cornerRadius(10)
            .shadow(color: Color.gray, radius: 1.0, x: CGFloat(4), y: CGFloat(4))
            .overlay(Text("Text"))
        }
    }
}

Result:

enter image description here

For more read this page.

Related