iOS根视图控制器切换动画异常:上滑淡出时黑屏,动画后才显示新视图
根视图控制器切换动画问题修复
问题原因
你的代码核心问题是动画过程中没有将新根控制器(vcB)的视图加入层级,而是在动画结束后才设置根VC,导致动画时窗口没有有效视图,显示黑屏。同时vcB的视图从未被主动添加到界面,自然无法在动画过程中显示。
解决方案
正确的流程应该是:先将vcB设为根VC(让它的视图加载到窗口),再把vcA的视图盖在vcB上方,最后执行vcA的上滑淡出动画,动画完成后彻底移除vcA的视图和层级。这样动画过程中vcB已经在后台可交互,且能正常显示。
修正后的代码
private func getCurrentWindow() -> UIWindow? { // 兼容iOS13+的SceneDelegate和iOS12及以下的AppDelegate if #available(iOS 13.0, *) { return UIApplication.shared.connectedScenes .filter({ $0.activationState == .foregroundActive }) .compactMap({ $0 as? UIWindowScene }) .first? .windows .first(where: { $0.isKeyWindow }) } else { return UIApplication.shared.delegate?.window ?? nil } } private func setNewRootViewController(_ viewController: UIViewController) { guard let window = getCurrentWindow() else { return } // 1. 先设置vcB为根视图控制器,此时它的视图会被加载到窗口 window.rootViewController = viewController window.layoutIfNeeded() // 确保vcB的视图完成布局 // 2. 将vcA的视图添加到窗口最上层,暂时盖住vcB window.addSubview(self.view) // 3. 执行vcA的上滑+淡出动画 UIView.animate(withDuration: 0.5, animations: { self.view.alpha = 0 self.view.transform = CGAffineTransform(translationX: 0, y: -self.view.frame.height) }) { [weak self] _ in guard let self = self else { return } // 4. 动画完成后彻底清理vcA的视图和层级 self.view.removeFromSuperview() self.removeFromParent() } }
关键细节说明
- 提前设置根VC:动画前就将vcB设为根,保证它的生命周期正常,用户在动画过程中可以操作vcB的界面
- 视图层级管理:把vcA的视图加到窗口最上层,确保动画时vcA在vcB上方,滑走后自然露出vcB
- 兼容多场景:
getCurrentWindow方法适配了iOS13+的Scene架构,避免只依赖AppDelegate导致的适配问题 - 避免循环引用:动画闭包中使用
weak self防止内存泄漏 - 不中断vcA内容:动画过程中vcA的视图始终存在,视频播放、其他动画不会被中断,直到动画完成后才被彻底移除
内容的提问来源于stack exchange,提问作者ArtisticEndeavor
相关产品推荐
相关产品推荐

