关闭SFSafariViewController后Page Sheet显示异常的解决方法问询
Hey,这个问题我太熟悉了——那种从SFSafariViewController回来时,原Page Sheet先全屏闪一下再缩回去的体验确实很糟。其实这是因为系统在present全屏的SFSafariViewController时,临时修改了原视图控制器的呈现样式,关闭后恢复时出现了动画冲突。咱们可以通过几个简单的步骤解决这个问题:
解决方案步骤
1. 确保原ViewController以Page Sheet正确初始化呈现
首先,在你present这个ViewController的时候,必须明确设置它的modalPresentationStyle为.pageSheet,这是基础:
let yourViewController = YourViewController() yourViewController.modalPresentationStyle = .pageSheet // 如果你想禁止用户通过下拉手势关闭这个Page Sheet,可以加上下面这行 yourViewController.isModalInPresentation = true present(yourViewController, animated: true, completion: nil)
2. 在present SFSafariViewController时,利用其dismiss回调强制恢复样式
当你在原ViewController中点击按钮打开SFSafariViewController时,设置它的dismissCompletion回调,在关闭后直接强制将原控制器的呈现样式设回.pageSheet:
import SafariServices class YourViewController: UIViewController { @IBAction func openWebButtonTapped(_ sender: UIButton) { guard let targetURL = URL(string: "https://your-target-url.com") else { return } let safariVC = SFSafariViewController(url: targetURL) // 保持SFSafariViewController的全屏呈现(默认就是,也可以显式设置) safariVC.modalPresentationStyle = .fullScreen // 设置关闭后的回调,强制恢复Page Sheet样式 safariVC.dismissCompletion = { [weak self] in guard let self = self else { return } self.modalPresentationStyle = .pageSheet // 触发动画化的布局更新,确保样式平滑生效,避免闪屏 UIView.animate(withDuration: 0.25) { self.presentationController?.containerView?.layoutIfNeeded() } } present(safariVC, animated: true, completion: nil) } }
3. 额外保险:在视图生命周期中强制锁定样式
为了防止其他意外情况(比如系统内部的样式重置)导致状态变化,你可以在原ViewController的viewWillAppear方法中再次强制设置样式,确保每次视图出现时都是Page Sheet:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 每次视图即将显示时,锁定为Page Sheet样式 modalPresentationStyle = .pageSheet }
原理说明
这个问题的核心是:SFSafariViewController默认以全屏方式呈现,系统会临时将原Page Sheet控制器的呈现样式改为全屏以适配。当关闭SFSafariViewController时,系统尝试恢复原样式,但这个恢复过程会产生可见的动画闪屏。通过在关闭后立即强制设置原控制器的样式,并触发动画化的布局更新,我们可以跳过系统的默认恢复动画,直接保持Page Sheet状态。
内容的提问来源于stack exchange,提问作者Marcus Houpt
相关产品推荐
相关产品推荐

