swiftui - 在 SwiftUI 中重新创建蒙版模糊效果

标签 swiftui uikit

我已经创建了这个蒙版模糊效果(下面的代码),它在 SwiftUI 中运行,但使用 UIViewRepresentable 进行蒙版,是否可以重新创建相同的效果,但只是在纯 SwiftUI 中?
Blur with mask
这是当前的代码,如果你运行它,用你的手指在屏幕上拖动,这会移动蒙版以显示在下面。

import SwiftUI
import UIKit

struct TestView: View {

  @State var position: CGPoint = .zero

  var simpleDrag: some Gesture {
    DragGesture()
      .onChanged { value in
        self.position = value.location
      }
  }

  var body: some View {
    ZStack {
  
      Circle()
        .fill(Color.green)
        .frame(height: 200)
  
      Circle()
        .fill(Color.pink)
        .frame(height: 200)
        .offset(x: 50, y: 100)
  
      Circle()
        .fill(Color.orange)
        .frame(height: 100)
        .offset(x: -50, y: 00)
  
      BlurView(style: .light, position: $position)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
  
    }
    .gesture(
      simpleDrag
    )

  }
}

struct BlurView: UIViewRepresentable {

  let style: UIBlurEffect.Style

  @Binding var position: CGPoint

  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),
    ])

    let clipPath = UIBezierPath(rect: UIScreen.main.bounds)

    let circlePath = UIBezierPath(ovalIn: CGRect(x: 100, y: 0, width: 200, height: 200))

    clipPath.append(circlePath)

    let layer = CAShapeLayer()
    layer.path = clipPath.cgPath
    layer.fillRule = .evenOdd
    view.layer.mask = layer
    view.layer.masksToBounds = true

    return view
  }

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

    let clipPath = UIBezierPath(rect: UIScreen.main.bounds)

    let circlePath = UIBezierPath(ovalIn: CGRect(x: position.x, y: position.y, width: 200, height: 200))

    clipPath.append(circlePath)

    let layer = CAShapeLayer()
    layer.path = clipPath.cgPath
    layer.fillRule = .evenOdd
    uiView.layer.mask = layer
    uiView.layer.masksToBounds = true

  }

}

struct TestView_Previews: PreviewProvider {
  static var previews: some View {
    TestView()
  }
}

最佳答案

我想我几乎有一个解决方案,我可以使用 View 修改器使用 ZStack 将结果渲染两次,我可以模糊一个 View ,并使用蒙版在其中敲一个洞。
blur

import SwiftUI

struct TestView2: View {

  @State var position: CGPoint = .zero

  var simpleDrag: some Gesture {
    DragGesture()
      .onChanged { value in
        self.position = value.location
      }
  }

  var body: some View {
    ZStack {
  
      Circle()
        .fill(Color.green)
        .frame(height: 200)
  
      Circle()
        .fill(Color.pink)
        .frame(height: 200)
        .offset(x: 50, y: 100)
  
      Circle()
        .fill(Color.orange)
        .frame(height: 100)
        .offset(x: -50, y: 00)
    }
    .maskedBlur(position: $position)
    .gesture(
      simpleDrag
    )

  }
}

struct MaskedBlur: ViewModifier {

  @Binding var position: CGPoint

  /// Render the content twice
  func body(content: Content) -> some View {

    ZStack {
      content
  
      content
        .blur(radius: 10)
        .mask(
          Hole(position: $position)
            .fill(style: FillStyle(eoFill: true))
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        )
    }

  }
}

extension View {
  func maskedBlur(position: Binding<CGPoint>) -> some View {
    self.modifier(MaskedBlur(position: position))
  }
}

struct Hole: Shape {

  @Binding var position: CGPoint

  func path(in rect: CGRect) -> Path {
    var path = Path()

    path.addRect(UIScreen.main.bounds)

    path.addEllipse(in: CGRect(x: position.x, y: position.y, width: 200, height: 200))

    return path
  }
}


#if DEBUG

struct TestView2_Previews: PreviewProvider {
  static var previews: some View {
    TestView2()
  }
}

#endif

关于swiftui - 在 SwiftUI 中重新创建蒙版模糊效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65327747/

相关文章:

xamarin.ios - UImage.AsPNG() 线程安全吗?

ios - 将导航栏标题文本更改为自定义颜色?

ios - 如何判断一条语句是否需要放在DispatchQueue.main.async中?

ios - iOS 检查视网膜像素的工具或技术?

ios - SwiftUI 不能正确评估 elseif?

swift - 模拟并注入(inject) ObservableObject

swiftui - 有没有办法在 swiftui 中设置特定的文本样式,类似于您制作按钮样式的方式?

ios - 带有图像和文本的 SwiftUI 表单选择器

ios - 如何删除 SwiftUI NavigationView 中的默认导航栏空间

objective-c - 调整 UIToolbar 的大小以适合其项目?