Reputation: 1283
I'm the fullScreenCover to show a modal in my SwiftUI project.
However, I need to show the modal with a transparent and blurred background.
But I can't seem to be able to achieve this at all.
This is my code:
.fullScreenCover(isPresented: $isPresented) {
VStack(spacing: 20) {
Spacer()
.frame(maxWidth: .infinity, minHeight: 100)
.background(Color.black)
.opacity(0.3)
//Text("modal")
}
.background(SecondView()) // << helper !!
}
And I have this on the same View:
struct BackgroundBlurView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIVisualEffectView(effect: UIBlurEffect(style: .light))
DispatchQueue.main.async {
view.superview?.superview?.backgroundColor = .clear
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
The above code will open the fullscreen modal but its not transparent or blurred at all.
This is what I get:
is there something else I need to do?
Reference to where I got the above code from:
SwiftUI: Translucent background for fullScreenCover
Upvotes: 3
Views: 5576
Reputation: 53
Well there's an inbuilt view modifier in SwiftUI Below is a sample
MainView()
.blur(radius: <condition, if any> ? 10 : 0)
.animation(.easeInOut, value: <conditional value>) // for blurring effect
This worked like a charm in my case
Upvotes: 0
Reputation: 18914
@Asperi answer from here is totally correct. Just need to add alpha to blur view.
struct BackgroundBlurView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIVisualEffectView(effect: UIBlurEffect(style: .light))
view.alpha = 0.5 //< --- here
DispatchQueue.main.async {
view.superview?.superview?.backgroundColor = .clear
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
Another approach is to use ViewControllerHolder reference link
struct ViewControllerHolder {
weak var value: UIViewController?
}
struct ViewControllerKey: EnvironmentKey {
static var defaultValue: ViewControllerHolder {
return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)
}
}
extension EnvironmentValues {
var viewController: UIViewController? {
get { return self[ViewControllerKey.self].value }
set { self[ViewControllerKey.self].value = newValue }
}
}
extension UIViewController {
func present<Content: View>(backgroundColor: UIColor = UIColor.clear, @ViewBuilder builder: () -> Content) {
let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
toPresent.view.backgroundColor = backgroundColor
toPresent.modalPresentationStyle = .overCurrentContext
toPresent.modalTransitionStyle = .coverVertical
toPresent.rootView = AnyView(
builder()
.environment(\.viewController, toPresent)
)
//Add blur efect
let blurEfect = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
blurEfect.frame = UIScreen.main.bounds
blurEfect.alpha = 0.5
toPresent.view.insertSubview(blurEfect, at: 0)
self.present(toPresent, animated: true, completion: nil)
}
}
struct ContentViewNeo: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
var body: some View {
VStack {
Text("Background screen")
Button("Open") {
viewControllerHolder?.present(builder: {
SheetView()
})
}
}
}
}
struct SheetView: View {
var body: some View {
Text("Sheet view")
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
Upvotes: 5
Reputation: 52387
I removed some extraneous stuff and made sure that there was content in the background that you could see peeking through.
Without the alpha
that is suggested in a different answer, the effect is very subtle, but there.
struct ContentView : View {
@State var isPresented = false
var body: some View {
VStack {
Text("Some text")
Spacer()
Text("More")
Spacer()
Button(action: {
isPresented.toggle()
}) {
Text("Show fullscreenview")
}
.fullScreenCover(isPresented: $isPresented) {
Text("modal")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(BackgroundBlurView())
}
Spacer()
Text("More text")
}
}
}
struct BackgroundBlurView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIVisualEffectView(effect: UIBlurEffect(style: .light))
DispatchQueue.main.async {
view.superview?.superview?.backgroundColor = .clear
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
Note the extremely subtle blue you can see from the Button
shining through. More obvious in dark mode.
The effect may get more dramatic as you add more color and content to the background view. Adding alpha
certainly makes things more obvious, though.
Upvotes: 5