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

Dar*_*eat 6 swift swiftui

我想模糊视图的背景,但是不想闯入UIKit来完成它(例如a UIVisualEffectView)。我正在研究文档,却一无所获,似乎没有办法实时剪切背景并对其应用效果。我是错误的还是以错误的方式调查它?

Moj*_*ini 90

1. Native SwiftUI方式:

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

Image("BG")
   .blur(radius: 20)
Run Code Online (Sandbox Code Playgroud)

模糊演示 注意视图的顶部和底部

请注意,您可以将Group多个视图合并在一起。


2. 视觉效果视图:

你可以UIVisualEffectView从 UIKit带上级长:

VisualEffectView(effect: UIBlurEffect(style: .dark))
Run Code Online (Sandbox Code Playgroud)

使用这个小结构:

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

电动汽车演示


3. iOS 15:材料

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

.background(.ultraThinMaterial)
Run Code Online (Sandbox Code Playgroud)

演示

  • 我喜欢你可以模糊几乎任何东西! (4认同)
  • 这是我见过的最简洁的 Representable 用法。很有帮助。 (3认同)

cyb*_*bot 18

最简单的办法就是在这里由理查德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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中的某个地方使用它,比如背景:

    //...
    MyView()
        .background(Blur(style: .systemUltraThinMaterial))
Run Code Online (Sandbox Code Playgroud)


Mat*_*ini 13

我还没有找到在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>) {

    }

}
Run Code Online (Sandbox Code Playgroud)

演示

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

                }
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我曾经ZStack在上面放一些视图。

ZStack {
 // List
 ZStack {
    // Blurred View
    // Text
 }
}
Run Code Online (Sandbox Code Playgroud)

最终看起来像这样:

在此处输入图片说明

  • 这会使视图中的内容模糊,但是我正在寻找可以使基础内容模糊的东西,就像UI VisualEffectView或navigationController的工作方式一样,而您可以使项目模糊其覆盖的内容,并且仅在BlurringView的框架内而不是BlurringView的子内容。我想更像BlendMode的工作方式。 (2认同)

Sh_*_*han 11

iOS 15 中的新功能,SwiftUI有一个非常简单的等效项UIVisualEffectView,它结合了ZStackbackground()修饰符和一系列内置材质。

\n
ZStack {\n    Image("niceLook")\n\n    Text("Click me")\n        .padding()\n        .background(.thinMaterial)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

您可以使用多种材质类型之一来调整材质 \xe2\x80\x93 的 \xe2\x80\x9cthickness\xe2\x80\x9d 多少背景内容透过 \xe2\x80\x93 发光。从最薄到最厚,它们是:

\n
.ultraThinMaterial\n.thinMaterial\n.regularMaterial\n.thickMaterial\n.ultraThickMaterial\n
Run Code Online (Sandbox Code Playgroud)\n


Dmi*_*gin 9

我发现了一个有趣的技巧来解决这个问题。我们可以用它UIVisualEffectView来制作其背景的实时“快照”。但这个“快照”将会产生应用效果UIVisualEffectView。我们可以使用避免应用这种效果UIViewPropertyAnimator

我没有发现这个黑客的任何副作用。您可以在这里找到我的解决方案:我的 GitHub Gist

代码

/// A View in which content reflects all behind it
struct BackdropView: UIViewRepresentable {

    func makeUIView(context: Context) -> UIVisualEffectView {
        let view = UIVisualEffectView()
        let blur = UIBlurEffect()
        let animator = UIViewPropertyAnimator()
        animator.addAnimations { view.effect = blur }
        animator.fractionComplete = 0
        animator.stopAnimation(false)
        animator.finishAnimation(at: .current)
        return view
    }
    
    func updateUIView(_ uiView: UIVisualEffectView, context: Context) { }
    
}

/// A transparent View that blurs its background
struct BackdropBlurView: View {
    
    let radius: CGFloat
    
    @ViewBuilder
    var body: some View {
        BackdropView().blur(radius: radius)
    }
    
}
Run Code Online (Sandbox Code Playgroud)

用法

ZStack(alignment: .leading) {
    Image(systemName: "globe")
        .resizable()
        .frame(width: 200, height: 200)
        .foregroundColor(.accentColor)
        .padding()
    BackdropBlurView(radius: 6)
        .frame(width: 120)
}
Run Code Online (Sandbox Code Playgroud)

使用示例

  • 射击,只需将 `opaque: true` 参数添加到模糊函数和中提琴!! (2认同)

byJ*_*van 6

resizable()正如@mojtaba 所提到的,当您与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


        }
  }
Run Code Online (Sandbox Code Playgroud)

结果: SwiftUI 图像蓝色技巧

  • 您可以向“.blur”修饰符添加另一个参数。如果您使用“.blur(radius: 5, opaque: true)”,它应该会删除白色阴影。 (6认同)