有没有一种方法可以在 SwiftUI 中模糊背景?

Is there a method to blur a background in SwiftUI?

我想模糊视图的背景,但不想进入 UIKit 来完成它(例如 UIVisualEffectView)我正在翻阅文档,但似乎一无所获无法实时剪辑背景并对其应用效果。是我错了还是看错了?

我还没有找到在 SwiftUI 中实现这一点的方法,但您可以通过 UIViewRepresentable 协议使用 UIKit 的东西。

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>) {

    }

}

演示:

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")

                }
            }
        }
    }

}

我用 ZStack 在上面放了视图。

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

最后看起来像这样:

1。原生 SwiftUI 方式:

只需在需要模糊的任何内容上添加 .blur() 修饰符,例如:

Image("BG")
   .blur(radius: 20)

注意视图的顶部和底部

请注意您可以Group多个视图并将它们模糊在一起。


2。视觉效果视图:

你可以从 UIKit 中引入 prefect UIVisualEffectView:

VisualEffectView(effect: UIBlurEffect(style: .dark))

有了这个小结构:

struct VisualEffectView: UIViewRepresentable {
    var effect: UIVisualEffect?
    func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView { UIVisualEffectView() }
    func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) { uiView.effect = effect }
}


3。 iOS15:材料

您可以通过一行代码使用iOS预定义材料:

.background(.ultraThinMaterial)

最简单的方法是 Richard Mullinix 的 here

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)
    }
}

然后只需在您的代码中的某处使用它,例如背景:

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

正如@mojtaba 所提到的,当您设置 resizable() 和 blur() 时,在图像顶部看到白色阴影是非常奇怪的。

一个简单的技巧是将图像填充提高到 -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


        }
  }

结果:

@State private var amount: CGFLOAT = 0.0

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

使用“Opaque: true”和模糊功能将消除白噪声

有一个非常有用但不幸的是私人的(感谢Apple)class CABackdropLayer

它会复制下面的图层,我发现它在使用blend mode或滤镜时很有用,它也可以用于模糊效果

代码

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)
  }
}

用法

struct Example: View {

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

Source

iOS 15 中的新增功能,SwiftUI 具有与 UIVisualEffectView 相当简单的等效项,它结合了 ZStackbackground() 修饰符和范围内置 materials.

ZStack {
    Image("niceLook")

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

您可以使用几种 material 类型中的一种来调整 material 的“厚度”——有多少背景内容可以透过。从最薄到最厚分别是:

.ultraThinMaterial
.thinMaterial
.regularMaterial
.thickMaterial
.ultraThickMaterial
Button("Test") {}
        .background(Rectangle().fill(Color.red).blur(radius: 20))