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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 14:25:20