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
相关产品推荐
相关产品推荐

