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

如何修改/禁用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 17:31:09