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

iOS 15中如何为sheetPresentationController设置自定义Detents?有无替代方案?

iOS 15 实现自定义Sheet高度的替代方案

iOS 15本身没有官方API支持自定义Sheet的detent高度,只能通过一些变通方式实现类似效果,给你几个靠谱的替代思路:

1. 自己封装带拖拽的自定义Sheet容器

放弃系统的sheetPresentationController,自己写一个模态弹窗容器,完全控制高度和交互逻辑:

  • 先搞一个半透明背景的ViewController当容器,添加全屏的拖拽手势识别器
  • 把你要展示的objVC作为子控制器加到容器里,初始把它的view高度设成550,贴底部布局
  • 处理拖拽手势:根据手指偏移实时调整子view的高度,限制最小(比如550)和最大(屏幕高度)值
  • 拖拽结束时做吸附逻辑,比如松手后回到550或者全屏,同时处理背景点击关闭的逻辑

简化代码示例:

// 自定义容器控制器
class CustomSheetContainerVC: UIViewController {
    private let contentVC: UIViewController
    private var contentViewHeightConstraint: NSLayoutConstraint!
    
    init(contentVC: UIViewController) {
        self.contentVC = contentVC
        super.init(nibName: nil, bundle: nil)
        modalPresentationStyle = .overFullScreen
        modalTransitionStyle = .crossDissolve
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupBackground()
        setupContentView()
        setupPanGesture()
    }
    
    private func setupBackground() {
        view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        let tap = UITapGestureRecognizer(target: self, action: #selector(dismissSheet))
        view.addGestureRecognizer(tap)
    }
    
    private func setupContentView() {
        addChild(contentVC)
        view.addSubview(contentVC.view)
        contentVC.didMove(toParent: self)
        
        contentVC.view.translatesAutoresizingMaskIntoConstraints = false
        contentViewHeightConstraint = contentVC.view.heightAnchor.constraint(equalToConstant: 550)
        NSLayoutConstraint.activate([
            contentVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            contentVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            contentVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            contentViewHeightConstraint
        ])
        contentVC.view.layer.cornerRadius = 22
        contentVC.view.clipsToBounds = true
    }
    
    private func setupPanGesture() {
        let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
        contentVC.view.addGestureRecognizer(pan)
    }
    
    @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
        let translation = gesture.translation(in: view)
        let newHeight = max(550, view.bounds.height + translation.y)
        
        switch gesture.state {
        case .changed:
            contentViewHeightConstraint.constant = newHeight
        case .ended:
            // 吸附逻辑:拖拽超过屏幕70%高度就全屏,否则回到550
            let shouldExpand = newHeight > view.bounds.height * 0.7
            contentViewHeightConstraint.constant = shouldExpand ? view.bounds.height : 550
            UIView.animate(withDuration: 0.3) {
                self.view.layoutIfNeeded()
            }
        default: break
        }
        gesture.setTranslation(.zero, in: view)
    }
    
    @objc private func dismissSheet() {
        dismiss(animated: true)
    }
}

// 使用方式:替换原来的sheet展示逻辑
// present(CustomSheetContainerVC(contentVC: objVC), animated: true)

2. 利用系统medium detent调整内容布局

如果不想自己写容器,可以利用iOS 15的.medium() detent,通过调整内容的内边距让视觉上达到自定义高度:

  • 给objVC的view套一个scrollView或者contentView,把实际内容放在里面
  • 设置contentView的高度为550,然后调整布局让contentView在medium sheet里居中显示
  • 关闭sheet的滚动扩展,避免滚动触发sheet变大

修改你现有代码的else分支:

if let sheet = objVC?.sheetPresentationController {
    if #available(iOS 16.0, *) {
        sheet.detents = [
            .custom { _ in
                return 550
            }
        ]
    } else {
        sheet.detents = [.medium(), .large()]
        // 给objVC的内容做适配调整
        let contentView = UIView()
        contentView.backgroundColor = .white
        contentView.translatesAutoresizingMaskIntoConstraints = false
        objVC.view.addSubview(contentView)
        
        NSLayoutConstraint.activate([
            contentView.heightAnchor.constraint(equalToConstant: 550),
            contentView.leadingAnchor.constraint(equalTo: objVC.view.leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: objVC.view.trailingAnchor),
            contentView.centerYAnchor.constraint(equalTo: objVC.view.centerYAnchor)
        ])
        objVC.view.backgroundColor = .clear
    }
    sheet.largestUndimmedDetentIdentifier = .medium
    sheet.prefersGrabberVisible = true
    sheet.preferredCornerRadius = 22
    sheet.prefersScrollingExpandsWhenScrolledToEdge = false // iOS15下关闭滚动扩展
    sheet.prefersEdgeAttachedInCompactHeight = true
    sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
    sheet.selectedDetentIdentifier = .medium        
}

3. 慎用私有API(不推荐)

iOS 15的sheetPresentationController有私有方法可以设置自定义高度,但这种方法过审风险极高,而且系统版本更新可能直接崩溃,正式项目别碰,仅作技术参考。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 13:28:11