2

I am trying to have a semi-transparent blurred overlaying view but the blur creates a fuzzy edge and I'd like it to be sharp outlining the overlay shape, ie clip it.

struct TestBlur : View {
    var body : some View {
        HStack {
            VStack {
                Spacer()
                Text("Hello World")
                Spacer()
            }
            .frame(width: 128)
            .background(Color.red.opacity(0.5).blur(radius: 16).clipShape(Rectangle()))
            Spacer()
        }
        .background(Color.yellow)
    }
}

enter image description here

I want the edge of the red overlay to be like so:

enter image description here

In essence I want the red view to blur anything below it and have a sharp edge:

enter image description here

Using @Asperi's BackgroundBlurView also doesn't work, there's no blur done (maybe I am not using this right):

    var body : some View {
        ZStack {
            VStack {
                ForEach(0..<40) { i in
                    Text("ABCDEFGHIKLMNOPQRSTUVWXYZ ABCDEFGHIKLMNOPQRSTUVWXYZ ABCDEFGHIKLMNOPQRSTUVWXYZ ABCDEFGHIKLMNOPQRSTUVWXYZ ABCDEFGHIKLMNOPQRSTUVWXYZ ")
                }
                .rotationEffect(Angle.init(degrees: 0))
            }
            .opacity(0.9)
            .background(Color.yellow)
            
            HStack {
                // Trying to make the below VStack have a semi-transparent background and blur all content below it
                // but the VStack needs to have a sharp edge, not fuzzy.
                VStack {
                    Spacer()
                    Text("Hello World")
                    Spacer()
                }
                .frame(width: 128)
                .background(Color.red.opacity(0.5))
                .background(BackgroundBlurView().opacity(0.8))
                Spacer()
            }
        }
    }

struct BackgroundBlurView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIVisualEffectView(effect: UIBlurEffect(style: .light))
        DispatchQueue.main.async {
            view.superview?.superview?.backgroundColor = .clear
        }
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {}
}

Looks like this (lacks blur): enter image description here

andrewz
  • 4,729
  • 5
  • 49
  • 67
  • It is not clear for me what do you try to achieve, could you demo somehow? – Asperi Jan 05 '21 at 19:04
  • 1
    I don't think the code is accurate in capturing what I want: I want the portion under the red view to be semi-transparent and blurring all content visible below it. – andrewz Jan 05 '21 at 19:18
  • 1
    Clipping works with Xcode 12.1 / iOS 14.1 as on screenshot2. For screenshot3 I assume more appropriate to use UIVisualEffectView like in https://stackoverflow.com/a/64301261/12299030. – Asperi Jan 05 '21 at 19:54
  • @Asperi For some reason it doesn't work for me. But also that approach doesn't allow for a blur radius. – andrewz Jan 05 '21 at 20:29
  • 1
    @andrewz you should not change the alpha of a `UIVisualEffectView` – aheze Jan 05 '21 at 20:45
  • 1
    @aheze You're right - works if I don't change opacity. But then I can't tweak the transparency. It's a solution. – andrewz Jan 05 '21 at 21:03
  • @andrewz yeah, that is a drawback of `UIVisualEffectView`. You can change the style though, for example `UIBlurEffect(style: .extraLight)`. And if you absolutely have to, you can try using `UIViewPropertyAnimator` and set the `fractionComplete` as in this [answer](https://stackoverflow.com/a/43158884/14351818). But usually I just go with the default opacity. – aheze Jan 05 '21 at 21:14

0 Answers0