'Is there a method to blur a background in SwiftUI?

I'm looking to blur a view's background but don't want to have to break out into UIKit to accomplish it (eg. a UIVisualEffectView) I'm digging through docs and got nowhere, seemingly there is no way to live-clip a background and apply effects to it. Am I wrong or looking into it the wrong way?



Solution 1:[1]

I haven't found a way to achieve that in SwiftUI yet, but you can use UIKit stuff via UIViewRepresentable protocol.

struct BlurView: UIViewRepresentable {

    let style: UIBlurEffect.Style

    func makeUIView(context: UIViewRepresentableContext<BlurView>) -> UIView {
        let view = UIView(frame: .zero)
        view.backgroundColor = .clear
        let blurEffect = UIBlurEffect(style: style)
        let blurView = UIVisualEffectView(effect: blurEffect)
        blurView.translatesAutoresizingMaskIntoConstraints = false
        view.insertSubview(blurView, at: 0)
        NSLayoutConstraint.activate([
            blurView.heightAnchor.constraint(equalTo: view.heightAnchor),
            blurView.widthAnchor.constraint(equalTo: view.widthAnchor),
        ])
        return view
    }

    func updateUIView(_ uiView: UIView,
                      context: UIViewRepresentableContext<BlurView>) {

    }

}

Demo:

struct ContentView: View {

    var body: some View {
        NavigationView {
            ZStack {
                List(1...100) { item in
                    Rectangle().foregroundColor(Color.pink)
                }
                .navigationBarTitle(Text("A List"))
                ZStack {
                    BlurView(style: .light)
                        .frame(width: 300, height: 300)
                    Text("Hey there, I'm on top of the blur")

                }
            }
        }
    }

}

I used ZStack to put views on top of it.

ZStack {
 // List
 ZStack {
    // Blurred View
    // Text
 }
}

And ends up looking like this:

enter image description here

Solution 2:[2]

The simplest way is here by Richard Mullinix:

struct Blur: UIViewRepresentable {
    var style: UIBlurEffect.Style = .systemMaterial

    func makeUIView(context: Context) -> UIVisualEffectView {
        return UIVisualEffectView(effect: UIBlurEffect(style: style))
    }

    func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
        uiView.effect = UIBlurEffect(style: style)
    }
}

Then just use it somewhere in your code like background:

    //...
    MyView()
        .background(Blur(style: .systemUltraThinMaterial))

Solution 3:[3]

As mentioned by @mojtaba, it's very peculiar to see white shade at top of image when you set resizable() along with blur().

As simple trick is to raise the Image padding to -ve.

 var body: some View {

        return
            ZStack {

                Image("background_2").resizable()
                    .edgesIgnoringSafeArea(.all)
                    .blur(radius: 5)
                    .scaledToFill()
                    .padding(-20) //Trick: To escape from white patch @top & @bottom


        }
  }

Result: SwiftUI Image blue trick

Solution 4:[4]

New in iOS 15 , SwiftUI has a brilliantly simple equivalent to UIVisualEffectView, that combines ZStack, the background() modifier, and a range of built-in materials.

ZStack {
    Image("niceLook")

    Text("Click me")
        .padding()
        .background(.thinMaterial)
}

You can adjust the “thickness” of your material – how much of the background content shines through – by using one of several material types. From thinnest to thickest, they are:

.ultraThinMaterial
.thinMaterial
.regularMaterial
.thickMaterial
.ultraThickMaterial

Solution 5:[5]

@State private var amount: CGFLOAT = 0.0

var body: some View {
    VStack{
       Image("Car").resizable().blur(radius: amount, opaque: true)
    }
}

Using "Opaque: true" with blur function will eliminate white noise

Solution 6:[6]

Button("Test") {}
        .background(Rectangle().fill(Color.red).blur(radius: 20))

Solution 7:[7]

There is a very useful but unfortunately private (thanks Apple) class CABackdropLayer

It draws a copy of the layers below, I found it useful when using blend mode or filters, It can also be used for blur effect

Code

open class UIBackdropView: UIView {

  open override class var layerClass: AnyClass {
    NSClassFromString("CABackdropLayer") ?? CALayer.self
  }
}

public struct Backdrop: UIViewRepresentable {

  public init() {}

  public func makeUIView(context: Context) -> UIBackdropView {
    UIBackdropView()
  }

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

public struct Blur: View {

  public var radius: CGFloat
  public var opaque: Bool

  public init(radius: CGFloat = 3.0, opaque: Bool = false) {
    self.radius = radius
    self.opaque = opaque
  }

  public var body: some View {
    Backdrop()
      .blur(radius: radius, opaque: opaque)
  }
}

Usage

struct Example: View {

  var body: some View {
    ZStack {
      YourBelowView()
      YourTopView()
        .background(Blur())
        .background(Color.someColor.opacity(0.4))
    }
  }
}

Source

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Lindemann
Solution 3 byJeevan
Solution 4 Sh_Khan
Solution 5 Sheikh Wahab Mahmood
Solution 6 Fatemeh
Solution 7