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

时间:2019-06-15 13:50:05

标签: swift swiftui

我希望模糊视图的背景,但是不想闯入UIKit来完成它(例如UIVisualEffectView)。我正在浏览文档,却一无所获,看来那里无法实时剪辑背景并对其应用效果。我是错还是以错误的方式调查它?

7 个答案:

答案 0 :(得分:13)

最简单的方法是Richard Mullinix的here

struct Blur: UIViewRepresentable {
    let 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))

答案 1 :(得分:4)

原生SwiftUI方式:

您可以在任何需要模糊的地方添加.blur()修饰符,例如:

struct ContentView: View {

    var body: some View {
        ZStack {
            Image("BG")
                .resizable()
                .scaledToFill()
                .edgesIgnoringSafeArea(.all)
                .blur(radius: 20) // <- this is the important modifier. The rest is just for demo

            Text("Hello \nSwiftUI Blur Effect")
                .font(.largeTitle)
                .fontWeight(.black)
                .foregroundColor(.white)
        }
    }
}

SwiftUI Code 注意视图的顶部和底部

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


视觉效果视图:

您可以仅用5行代码来定义VisualEffectView

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

用法示例:

struct ContentView: View {

    var body: some View {
        ZStack {
            Image("BG")
                .resizable()
                .scaledToFill()
                .edgesIgnoringSafeArea(.all)

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

            Text("Hello \nVisual Effect View")
                .font(.largeTitle)
                .fontWeight(.black)
                .foregroundColor(.white)
        }
    }
}

Visual Effect View

答案 2 :(得分:3)

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

最终看起来像这样:

enter image description here

答案 3 :(得分:1)

如@mojtaba所述,在将resizable()和blur()一起设置时,在图像顶部看到白色阴影是非常奇怪的。

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


        }
  }

结果: SwiftUI Image blue trick

答案 4 :(得分:1)

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

ZStack {
    Image("niceLook")

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

您可以通过使用多种材料类型之一来调整材料的“厚度”——背景内容的透光程度。从最薄到最厚,它们是:

.ultraThinMaterial
.thinMaterial
.regularMaterial
.thickMaterial
.ultraThickMaterial

答案 5 :(得分:0)

@State private var amount: CGFLOAT = 0.0

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

使用具有模糊功能的“不透明:真”将消除白噪声

答案 6 :(得分:-1)

有一个非常有用但不幸的是私有(感谢 Apple)类 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

相关问题