Swift在SceneDelegate切换window.rootViewController出现黑屏闪屏问题
iOS 15下SceneDelegate切换rootViewController黑屏闪屏问题解决
问题概述
在SceneDelegate中切换window.rootViewController时出现毫秒级黑屏闪屏,显示流程为:启动页→瞬间黑屏→正常窗口,已尝试多种常规方案仍未解决,怀疑与iOS 15特性或操作遗漏有关。
已尝试无效方案
- 用
DispatchQueue.main.async {}包裹切换逻辑 - 提前设置Dummy ViewController作为过渡载体
- 给目标ViewController的view设置
backgroundColor = .white
针对性解决方案
1. 确保Window背景色与启动页一致
切换rootViewController时,若window本身未设置背景色,会短暂显示系统默认的黑色。在初始化window时直接设置与启动页匹配的背景色:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) // 设置为启动页的背景色,比如白色或启动页主题色 window.backgroundColor = .white self.window = window window.makeKeyAndVisible() }
2. 使用UIWindow的setRootViewController(_:options:)方法(iOS 13+)
直接赋值rootViewController可能触发系统隐式过渡逻辑,改用带选项的API更可控,即使设置0时长动画也能避免黑屏:
let targetVC = YourTargetViewController() // 无动画切换,避免突兀视觉变化 window?.setRootViewController(targetVC, options: UIWindow.TransitionOptions( animationCurve: .linear, duration: 0.0 ))
3. 延迟切换至App激活后执行
避免在scene(_:willConnectTo:options:)中立即切换,等App完全激活(sceneDidBecomeActive回调)后再处理,此时window状态更稳定:
private var hasConfiguredRootVC = false func sceneDidBecomeActive(_ scene: UIScene) { guard !hasConfiguredRootVC, let window = window else { return } hasConfiguredRootVC = true let targetVC = YourTargetViewController() targetVC.view.backgroundColor = window.backgroundColor window.rootViewController = targetVC }
4. 排查多Window冲突
检查App中是否存在未正确隐藏的其他window,确保只有主window处于key且visible状态,多余window会干扰显示层级。
示例完整代码
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? private var hasSetRootVC = false func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) // 匹配启动页背景色 window.backgroundColor = .white self.window = window window.makeKeyAndVisible() } func sceneDidBecomeActive(_ scene: UIScene) { guard !hasSetRootVC, let window = window else { return } hasSetRootVC = true let targetVC = HomeViewController() targetVC.view.backgroundColor = window.backgroundColor window.setRootViewController(targetVC, options: UIWindow.TransitionOptions( animationCurve: .linear, duration: 0.0 )) } }
内容的提问来源于stack exchange,提问作者husharoonie
相关产品推荐
相关产品推荐

