You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 16.4之前版本SwiftUI中实现sheet背景透明的替代方案

iOS 16.4 之前实现 Sheet 背景透明的替代方案

在iOS 16.4之前,SwiftUI原生的.sheet没有直接设置背景透明的API,想要实现相同效果,主要有两种可行方案:

方案一:基于UIKit包装系统Sheet(保留原生特性)

通过UIViewControllerRepresentable包装UIKit的UISheetPresentationController,可以实现背景透明同时保留系统Sheet的拖拽调整、拖拽关闭等原生特性。

实现代码

首先定义包装器:

struct TransparentSheet<Content: View>: UIViewControllerRepresentable {
    @Binding var isPresented: Bool
    let content: Content
    let detents: [UISheetPresentationController.Detent]
    
    func makeUIViewController(context: Context) -> UIHostingController<Content> {
        let hostingController = UIHostingController(rootView: content)
        hostingController.view.backgroundColor = .clear
        return hostingController
    }
    
    func updateUIViewController(_ uiViewController: UIHostingController<Content>, context: Context) {
        if isPresented, uiViewController.presentingViewController == nil {
            let sheet = uiViewController.sheetPresentationController
            sheet?.detents = detents
            sheet?.largestUndimmedDetentIdentifier = .medium // 可选:设置该尺寸下背景不暗化
            sheet?.prefersGrabberVisible = true // 可选:显示顶部拖拽条
            
            // 关键配置:确保视图和背景透明
            uiViewController.view.backgroundColor = .clear
            uiViewController.presentationController?.delegate = context.coordinator
        } else if !isPresented, uiViewController.presentingViewController != nil {
            uiViewController.dismiss(animated: true)
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate {
        let parent: TransparentSheet
        
        init(_ parent: TransparentSheet) {
            self.parent = parent
        }
        
        func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
            parent.isPresented = false
        }
        
        // 移除系统默认的背景暗化和容器背景
        func presentationController(_ presentationController: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
            let vc = UIViewController()
            vc.view.backgroundColor = .clear
            return vc
        }
    }
}

使用方式

给View添加扩展方便调用:

extension View {
    func transparentSheet<Content: View>(isPresented: Binding<Bool>, detents: [UISheetPresentationController.Detent], @ViewBuilder content: @escaping () -> Content) -> some View {
        self.background(TransparentSheet(isPresented: isPresented, content: content(), detents: detents))
    }
}

在页面中使用:

struct ContentView: View {
    @State private var showFormView = false
    
    var body: some View {
        Button("打开透明Sheet") {
            showFormView = true
        }
        .transparentSheet(isPresented: $showFormView, detents: [.medium(), .large()]) {
            FormView()
                .background(Color.clear) // 确保内容视图本身背景透明
        }
    }
}

方案二:纯SwiftUI自定义模态视图(灵活易实现)

如果不需要系统Sheet的原生交互特性,完全可以用SwiftUI的ZStack、动画和手势自己实现一个背景透明的模态视图,代码更简洁,也更灵活。

实现代码

struct ContentView: View {
    @State private var showFormView = false
    
    var body: some View {
        ZStack {
            Button("打开自定义透明模态") {
                showFormView = true
            }
            
            if showFormView {
                // 可选:背景遮罩,设为.clear则完全透明
                Color.black.opacity(0.3)
                    .ignoresSafeArea()
                    .onTapGesture {
                        showFormView = false
                    }
                
                FormView()
                    .frame(maxWidth: .infinity)
                    .background(Color.clear)
                    .cornerRadius(16)
                    .padding(.horizontal)
                    .transition(.move(edge: .bottom))
                    .offset(y: showFormView ? 0 : UIScreen.main.bounds.height)
            }
        }
        .animation(.easeInOut, value: showFormView)
    }
}

方案对比

  • 方案一:保留系统Sheet的所有原生交互(拖拽调整尺寸、拖拽关闭等),但需要编写UIKit相关代码,复杂度稍高。
  • 方案二:纯SwiftUI实现,代码简单易维护,但需要自己实现拖拽、尺寸调整等交互,适合需求简单的场景。

内容的提问来源于stack exchange,提问作者fs_tigre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 13:01:13