SwiftUI:全屏幕封面的半透明背景

yqlxgs2m  于 2023-01-08  发布在  Swift
关注(0)|答案(5)|浏览(257)

所以从技术上讲,我想显示一个正在加载的屏幕视图,我使用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()
                        }
                    }
                }
            }
        }
    }
}

问题是我无法使这个加载屏幕半透明。sheetpopover的行为相同。

jslywgbw

jslywgbw1#

这里是一个演示的可能方式。参数的视觉效果,你可以调整为您的需要。
使用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) {}
}
fhity93d

fhity93d2#

在f3dm76上构建答案:
我改变了它,这样后面的内容就不会 Flink (我在fullScreenCover后面加载惰性图像时就发生过这种情况)。另外,我想对全屏内容使用自定义过渡(或者在某些情况下根本没有动画),所以我也用这种方法删除了默认动画。

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) {}
    
}
ergxz8rk

ergxz8rk3#

Asperi的答案很漂亮,但如果你想让背景透明而不模糊,这里有你可以修改它的方法。为了方便起见,我还把代码移到了一个修改器中。(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) {}
}
3wabscal

3wabscal4#

也可以使用“材质”背景类型:

ZStack{
   ...
}
.background(.ultraThinMaterial)

有关更多用法,请参阅文档:https://developer.apple.com/documentation/swiftui/material

r7xajy2e

r7xajy2e5#

我发现这个更清洁的解决方案的 Flink 问题在清晰的背景。

struct ClearBackgroundView: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        return InnerView()
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
    }
    
    private class InnerView: UIView {
        override func didMoveToWindow() {
            super.didMoveToWindow()
            
            superview?.superview?.backgroundColor = .clear
        }
        
    }
}

用途

PresenterView()
    .fullScreenCover(isPresented: $isPresented) {
        PresentedView()
            .background(ClearBackgroundView())
    }

相关问题