在 SwiftUI 中重新创建蒙版模糊效果
Posted
技术标签:
【中文标题】在 SwiftUI 中重新创建蒙版模糊效果【英文标题】:Recreating a masked blur effect in SwiftUI 【发布时间】:2020-12-16 16:58:36 【问题描述】:我已经创建了这个蒙版模糊效果(下面的代码),它在 SwiftUI 中运行,但使用 UIViewRepresentable 进行蒙版,是否可以重新创建相同的效果,但只是在纯 SwiftUI 中?
这是当前代码,如果你运行它,用手指在屏幕上拖动,这会移动遮罩以显示其下方。
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()
【问题讨论】:
【参考方案1】:我想我几乎有一个解决方案,我可以使用 viewmodifer 使用 ZStack 将结果渲染两次,我可以模糊一个视图,并使用蒙版在其中敲一个洞。
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 中重新创建蒙版模糊效果的主要内容,如果未能解决你的问题,请参考以下文章