SwiftUI:fullScreenCover 的半透明背景

Son*_*yen 4 ios swift swiftui

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

问题是我无法使这个加载屏幕半透明。sheetpopover以同样的方式行事。

Pov*_*las 19

建立在 f3dm76 答案之上:

我更改了它,这样后面的内容就不会闪烁(这发生在我身上,因为全屏覆盖后面加载了延迟图像)。另外,我想对全屏内容使用自定义过渡(或者在某些情况下根本没有动画),因此我也用这种方法删除了默认动画。

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) {}
    
}
Run Code Online (Sandbox Code Playgroud)


小智 19

使用presentationBackground为模态框(fullScreenCover、sheet、popover)设置所需的背景。从文档中:

允许通过半透明样式显示演示文稿背后的视图。

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{
                    VStack {
                        ProgressView()
                        Button("Stop loading") { isLoading.toggle() }
                    }
                }
                .presentationBackground(.black.opacity(0.5))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可用性

@available(iOS 16.4, macOS 13.3, tvOS 16.4, watchOS 9.4, *)
Run Code Online (Sandbox Code Playgroud)


Asp*_*eri 17

这是可能的方式的演示。您可以根据需要调整视觉效果参数。

使用 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) {}
}
Run Code Online (Sandbox Code Playgroud)

  • 你知道如何关闭动画吗? (3认同)
  • 这对我不起作用。大家对此还有其他解决办法吗? (2认同)

Ahm*_*san 12

我找到了这个更干净的解决方案,可以解决清晰背景中的闪烁问题。

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
        }
        
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

PresenterView()
    .fullScreenCover(isPresented: $isPresented) {
        PresentedView()
            .background(ClearBackgroundView())
    }
Run Code Online (Sandbox Code Playgroud)


f3d*_*m76 9

更新:请使用上面 Povilas 的答案以避免屏幕闪烁问题

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) {}
}
Run Code Online (Sandbox Code Playgroud)