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

在SwiftUI中封装UISheetPresentationController实现半屏模态弹窗问题求助

iOS 15 UISheetPresentationController SwiftUI 封装方案

首先纠正核心实现误区:

  • UIViewControllerRepresentable 协议要求返回的是 UIViewController 实例,而非 UISheetPresentationController 本身,后者是 UIKit 中控制模态页展示样式的附属对象,不需要手动初始化。
  • 模态弹出的 UIViewController 会自动生成 UISheetPresentationController 实例,直接访问控制器的对应属性即可,不需要手动传入 presentedViewController 和 presenting 参数初始化。

完整实现代码

import SwiftUI
import UIKit

struct KitSheet<Content: View>: UIViewControllerRepresentable {
    // 弹窗承载的SwiftUI内容
    let content: Content
    // 支持的弹窗高度尺寸,默认提供中等、最大两种
    var detents: [UISheetPresentationController.Detent] = [.medium(), .large()]
    // 是否展示顶部拖拽条
    var showsGrabber: Bool = true
    
    func makeUIViewController(context: Context) -> UIViewController {
        // 创建承载SwiftUI内容的Hosting控制器
        let hostingController = UIHostingController(rootView: content)
        // 直接获取系统自动生成的UISheetPresentationController实例
        guard let sheetController = hostingController.sheetPresentationController else {
            return hostingController
        }
        // 配置弹窗样式
        sheetController.detents = detents
        sheetController.prefersGrabberVisible = showsGrabber
        sheetController.delegate = context.coordinator
        return hostingController
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        // 状态更新时同步刷新弹窗配置
        guard let sheetController = uiViewController.sheetPresentationController else { return }
        sheetController.detents = detents
        sheetController.prefersGrabberVisible = showsGrabber
    }
    
    // 实现协调器处理代理回调
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject, UISheetPresentationControllerDelegate {
        // 按需实现UISheetPresentationControllerDelegate的代理方法即可
    }
}

使用示例

直接配合SwiftUI原生的sheet修饰符使用即可:

struct DemoView: View {
    @State private var isSheetPresented = false
    
    var body: some View {
        Button("唤起半屏弹窗") {
            isSheetPresented.toggle()
        }
        .sheet(isPresented: $isSheetPresented) {
            KitSheet(
                content: VStack(spacing: 30) {
                    Text("半屏弹窗内容")
                        .font(.title)
                    Button("关闭弹窗") {
                        isSheetPresented.toggle()
                    }
                    .foregroundColor(.blue)
                }
                .padding(.top, 20),
                detents: [.medium()],
                showsGrabber: true
            )
            .ignoresSafeArea()
        }
    }
}

补充说明

如果需要自定义模态弹出逻辑,可通过响应链获取当前应用顶层的UIViewController作为presentingViewController,不需要手动传入占位参数初始化UISheetPresentationController。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 22:36:04