So technically I want to show a loading screen view. I'm using fullScreenCover
.
struct ContentView: View {
@State private var isLoading = false
var body: some View {
VStack {
Text("Hello there")
Button("Start loading") {
isLoading.toggle()
}
.fullScreenCover(isPresented: $isLoading) {
ZStack{
Color.black.opacity(0.5).edgesIgnoringSafeArea(.all)
VStack {
ProgressView()
Button("Stop loading") {
isLoading.toggle()
}
}
}
}
}
}
}
The problem is that I cannot make this loading screen translucent. sheet
or popover
behave the same way.
Here is a demo of possible way. Parameters of visual effect you can tune for your needs.
Tested with Xcode 12 / iOS 14.
// ... other code
.fullScreenCover(isPresented: $isLoading) {
ZStack{
Color.black.opacity(0.5).edgesIgnoringSafeArea(.all)
VStack {
ProgressView()
Button("Stop loading") {
isLoading.toggle()
}
}
}
.background(BackgroundBlurView())
}
}
}
}
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) {}
}
Building on top of f3dm76 answer:
I changed it so content behind would not flicker (that happened to me with lazy images loading behind fullScreenCover). Also I wanted to use custom transitions for full screen content (or in some cases no animation at all), so I removed default animations with this approach as well.
extension View {
func transparentNonAnimatingFullScreenCover<Content: View>(isPresented: Binding<Bool>, content: @escaping () -> Content) -> some View {
modifier(TransparentNonAnimatableFullScreenModifier(isPresented: isPresented, fullScreenContent: content))
}
}
private struct TransparentNonAnimatableFullScreenModifier<FullScreenContent: View>: ViewModifier {
@Binding var isPresented: Bool
let fullScreenContent: () -> (FullScreenContent)
func body(content: Content) -> some View {
content
.onChange(of: isPresented) { isPresented in
UIView.setAnimationsEnabled(false)
}
.fullScreenCover(isPresented: $isPresented,
content: {
ZStack {
fullScreenContent()
}
.background(FullScreenCoverBackgroundRemovalView())
.onAppear {
if !UIView.areAnimationsEnabled {
UIView.setAnimationsEnabled(true)
}
}
.onDisappear {
if !UIView.areAnimationsEnabled {
UIView.setAnimationsEnabled(true)
}
}
})
}
}
private struct FullScreenCoverBackgroundRemovalView: UIViewRepresentable {
private class BackgroundRemovalView: UIView {
override func didMoveToWindow() {
super.didMoveToWindow()
superview?.superview?.backgroundColor = .clear
}
}
func makeUIView(context: Context) -> UIView {
return BackgroundRemovalView()
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
Asperi's answer is beautiful, but in case you want background to be transparent and not blurred, here is how you can modify it. I also moved the code into a modifier for convenience. (xcode 13.3, iOS 15.4.1)
extension View {
func transparentFullScreenCover<Content: View>(isPresented: Binding<Bool>, content: @escaping () -> Content) -> some View {
fullScreenCover(isPresented: isPresented) {
ZStack {
content()
}
.background(TransparentBackground())
}
}
}
struct TransparentBackground: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async {
view.superview?.superview?.backgroundColor = .clear
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With