如何修改/禁用sheetPresentationController全屏时presentingViewController的缩放后退行为?
解决Sheet全屏呈现时底层ViewController的推回缩放效果
当使用sheetPresentationController呈现全屏sheet时,底层的presenting VC默认会出现缩放、变暗的"推回"效果,你可以通过以下几种方式修改或完全禁用该行为:
方法1:取消底层视图变暗(简单快速)
如果只需要取消变暗效果,保留缩放动画,直接设置sheetPresentationController的largestUndimmedDetentIdentifier为.full,这样当sheet切换到全屏detent时,底层视图会保持可见:
let sheetVC = YourSheetViewController() sheetVC.modalPresentationStyle = .pageSheet if let sheetPC = sheetVC.sheetPresentationController { sheetPC.detents = [.medium(), .full()] // 设置全屏时不暗化底层视图 sheetPC.largestUndimmedDetentIdentifier = .full } present(sheetVC, animated: true)
方法2:完全禁用缩放+变暗效果(自定义转场)
要彻底移除底层VC的缩放动画和变暗效果,需要自定义转场动画,替换系统默认的sheet转场逻辑:
步骤1:设置转场代理
在presenting VC中,为sheet VC指定自定义的transitioningDelegate:
let sheetVC = YourSheetViewController() sheetVC.modalPresentationStyle = .pageSheet if let sheetPC = sheetVC.sheetPresentationController { sheetPC.detents = [.medium(), .full()] } // 设置转场代理 sheetVC.transitioningDelegate = self present(sheetVC, animated: true)
步骤2:实现转场代理方法
让presenting VC遵循UIViewControllerTransitioningDelegate,返回自定义的动画控制器:
extension YourPresentingViewController: UIViewControllerTransitioningDelegate { // 自定义present动画 func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return CustomSheetPresentAnimator() } // 自定义dismiss动画 func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return CustomSheetDismissAnimator() } }
步骤3:编写自定义动画控制器
实现present和dismiss的动画逻辑,仅处理sheet视图的滑入滑出,不修改底层VC的状态:
// Present动画:sheet从底部滑入 class CustomSheetPresentAnimator: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.35 // 匹配系统默认动画时长 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let presentedView = transitionContext.view(forKey: .to) else { transitionContext.completeTransition(false) return } let container = transitionContext.containerView container.addSubview(presentedView) // 初始位置:屏幕底部 presentedView.frame = CGRect(x: 0, y: container.bounds.height, width: container.bounds.width, height: container.bounds.height) UIView.animate(withDuration: transitionDuration(using: transitionContext), options: .curveEaseOut) { presentedView.frame = container.bounds } completion: { _ in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) } } } // Dismiss动画:sheet滑回底部 class CustomSheetDismissAnimator: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.35 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let dismissedView = transitionContext.view(forKey: .from) else { transitionContext.completeTransition(false) return } UIView.animate(withDuration: transitionDuration(using: transitionContext), options: .curveEaseIn) { dismissedView.frame = CGRect(x: 0, y: transitionContext.containerView.bounds.height, width: transitionContext.containerView.bounds.width, height: transitionContext.containerView.bounds.height) } completion: { _ in dismissedView.removeFromSuperview() transitionContext.completeTransition(!transitionContext.transitionWasCancelled) } } }
方法3:仅在全屏detent时禁用效果
如果需要在非全屏detent(比如medium)保留默认效果,仅全屏时禁用,可以通过UISheetPresentationControllerDelegate动态调整:
步骤1:设置代理
let sheetVC = YourSheetViewController() sheetVC.modalPresentationStyle = .pageSheet if let sheetPC = sheetVC.sheetPresentationController { sheetPC.detents = [.medium(), .full()] sheetPC.delegate = sheetVC // 让sheetVC自己做代理 } present(sheetVC, animated: true)
步骤2:实现代理方法
让sheet VC遵循UISheetPresentationControllerDelegate,在detent切换时调整底层视图状态:
extension YourSheetViewController: UISheetPresentationControllerDelegate { func sheetPresentationController(_ sheetPresentationController: UISheetPresentationController, didChangeSelectedDetentIdentifier selectedDetentIdentifier: UISheetPresentationController.Detent.Identifier?) { UIView.animate(withDuration: 0.35) { if selectedDetentIdentifier == .full { // 全屏时恢复底层视图的原始大小,取消暗化 self.presentingViewController?.view.transform = .identity sheetPresentationController.largestUndimmedDetentIdentifier = .full } else { // 非全屏时恢复系统默认的缩放和暗化 self.presentingViewController?.view.transform = CGAffineTransform(scaleX: 0.9, y: 0.9) sheetPresentationController.largestUndimmedDetentIdentifier = nil } } } }
内容的提问来源于stack exchange,提问作者Warpling
相关产品推荐
相关产品推荐

