[英]Is there a method to blur a background in SwiftUI?
I'm looking to blur a view's background but don't want to have to break out into UIKit to accomplish it (eg. a UIVisualEffectView
) I'm digging through docs and got nowhere, seemingly there is no way to live-clip a background and apply effects to it.我正在寻找模糊视图的背景,但不想进入 UIKit 来完成它(例如UIVisualEffectView
)我正在挖掘文档但无处可去,似乎没有办法实时剪辑 a背景并对其应用效果。 Am I wrong or looking into it the wrong way?我错了还是以错误的方式看待它?
Just add .blur()
modifier on anything you need to be blurry like:只需在需要模糊的任何内容上添加.blur()
修饰符,例如:
Image("BG")
.blur(radius: 20)
Note the top and bottom of the view注意视图的顶部和底部
Note that you can Group
multiple views and blur them together.请注意,您可以对多个视图进行Group
并将它们模糊在一起。
You can bring the prefect UIVisualEffectView
from the UIKit:你可以从 UIKit 中引入完美的UIVisualEffectView
:
VisualEffectView(effect: UIBlurEffect(style: .dark))
With this tiny struct:使用这个小结构:
struct VisualEffectView: UIViewRepresentable {
var effect: UIVisualEffect?
func makeUIView(context: UIViewRepresentableContext<Self>) -> UIVisualEffectView { UIVisualEffectView() }
func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext<Self>) { uiView.effect = effect }
}
You can use iOS predefined materials with one line code:您可以使用一行代码使用 iOS 预定义材料:
.background(.ultraThinMaterial)
I haven't found a way to achieve that in SwiftUI yet, but you can use UIKit stuff via UIViewRepresentable
protocol.我还没有找到在 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>) {
}
}
Demo :演示:
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")
}
}
}
}
}
I used ZStack
to put views on top of it.我使用ZStack
将视图放在它上面。
ZStack {
// List
ZStack {
// Blurred View
// Text
}
}
And ends up looking like this:最终看起来像这样:
The simplest way is here by Richard Mullinix:最简单的办法就是在这里由理查德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)
}
}
Then just use it somewhere in your code like background:然后在你的代码中的某个地方使用它,比如背景:
//...
MyView()
.background(Blur(style: .systemUltraThinMaterial))
As mentioned by @mojtaba, it's very peculiar to see white shade at top of image when you set resizable()
along with blur().正如@mojtaba 所提到的,当您设置resizable()
和 blur() 时,在图像顶部看到白色阴影是非常奇特的。
As simple trick is to raise the Image padding to -ve.一个简单的技巧是将图像填充提高到 -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)
}
}
Using "Opaque: true" with blur function will eliminate white noise使用带有模糊功能的“Opaque: true”将消除白噪声
I have found an interesting hack to solve this problem.我发现了一个有趣的 hack 来解决这个问题。 We can use UIVisualEffectView
to make live "snapshot" of its background.我们可以使用UIVisualEffectView
制作其背景的实时“快照”。 But this "snapshot" will have an applied effect of UIVisualEffectView
.但是这个“快照”将具有UIVisualEffectView
的应用效果。 We can avoid applying this effect using UIViewPropertyAnimator
.我们可以使用UIViewPropertyAnimator
避免应用这种效果。
I didn't find any side effect of this hack.我没有发现这个 hack 的任何副作用。 You can find my solution here: my GitHub Gist你可以在这里找到我的解决方案: my GitHub Gist
/// A View which content reflects all behind it
struct BackdropView: UIViewRepresentable {
func makeUIView(context: Context) -> UIVisualEffectView {
let view = UIVisualEffectView()
let blur = UIBlurEffect(style: .extraLight)
let animator = UIViewPropertyAnimator()
animator.addAnimations { view.effect = blur }
animator.fractionComplete = 0
animator.stopAnimation(true)
animator.finishAnimation(at: .start)
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)
}
}
ZStack(alignment: .leading) {
Image(systemName: "globe")
.resizable()
.frame(width: 200, height: 200)
.foregroundColor(.accentColor)
.padding()
BackdropBlurView(radius: 6)
.frame(width: 120)
}
New in iOS 15 , SwiftUI
has a brilliantly simple equivalent to UIVisualEffectView
, that combines ZStack
, the background()
modifier, and a range of built-in materials.在 iOS 15 中, SwiftUI
有一个非常简单的UIVisualEffectView
等效UIVisualEffectView
,它结合了ZStack
、 background()
修饰符和一系列内置材料。
ZStack {
Image("niceLook")
Text("Click me")
.padding()
.background(.thinMaterial)
}
You can adjust the “thickness” of your material – how much of the background content shines through – by using one of several material types.您可以使用多种材质类型中的一种来调整材质的“厚度”——背景内容有多少透过。 From thinnest to thickest, they are:从最薄到最厚,它们是:
.ultraThinMaterial
.thinMaterial
.regularMaterial
.thickMaterial
.ultraThickMaterial
There is a very useful but unfortunately private (thanks Apple) class CABackdropLayer
有一个非常有用但不幸的是私有(感谢 Apple)类CABackdropLayer
It draws a copy of the layers below, I found it useful when using blend mode
or filters, It can also be used for blur effect它绘制了下面图层的副本,我发现它在使用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))
}
}
}
Button("Test") {}
.background(Rectangle().fill(Color.red).blur(radius: 20))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.