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

iOS10中AVPlayerViewController导致弹窗内底层模态视图控制器异常

解决iOS 10中AVPlayerViewController横屏后底层模态弹窗异常的问题

嘿,这个iOS 10的模态旋转bug我之前踩过坑!结合你的场景——竖屏应用里,层级是TabBar控制器(根)→A→弹窗B→AVPlayerViewController(AVP),当弹出AVP后旋转设备到横屏,底层的B弹窗出现异常,这其实是iOS 10特有的旋转事件传递和状态同步bug:当嵌套的模态控制器中存在支持横屏的实例时,底层固定竖屏的控制器会丢失正确的布局状态,导致界面错乱。

下面给你几个可行的解决方案,按推荐程度排序:

方案一:自定义AVPlayerViewController子类(最稳妥)

通过自定义AVP的旋转行为,确保它在消失时强制回到竖屏,避免影响底层控制器:

  1. 创建CustomAVPlayerViewController子类:
import AVKit

class CustomAVPlayerViewController: AVPlayerViewController {
    // 允许AVP自动旋转
    override var shouldAutorotate: Bool {
        return true
    }
    
    // 按需设置支持的方向,这里选除了倒竖屏的所有方向
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .allButUpsideDown
    }
    
    // 当AVP即将消失时,强制将设备转回竖屏
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        guard let window = UIApplication.shared.keyWindow else { return }
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
    }
}
  1. 在弹窗B中使用这个子类来弹出播放控制器,替换原生的AVPlayerViewController即可。

方案二:给弹窗B添加旋转监听与修复

如果不想自定义AVP子类,可以在弹窗B中监听旋转事件,在AVP活跃时强制修复布局:

  1. 在B的viewDidLoad中注册旋转通知:
override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(handleRotation),
        name: UIDevice.orientationDidChangeNotification,
        object: nil
    )
}
  1. 实现布局修复逻辑:
@objc private func handleRotation() {
    // 只有当AVP已经弹出时才处理
    guard presentedViewController is AVPlayerViewController else { return }
    // 延迟一点时间,等旋转动画完成后再修复布局
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()
    }
}

// 记得在销毁时移除通知
deinit {
    NotificationCenter.default.removeObserver(self)
}

方案三:全局控制旋转权限

通过根TabBarController的旋转代理方法,确保只有当前最上层的控制器能控制旋转方向,避免底层控制器被干扰:

  1. 自定义根TabBarController:
class CustomTabBarController: UITabBarController {
    override var shouldAutorotate: Bool {
        return selectedViewController?.shouldAutorotate ?? false
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return selectedViewController?.supportedInterfaceOrientations ?? .portrait
    }
}
  1. 在弹窗B中固定旋转设置:
class BViewController: UIViewController {
    override var shouldAutorotate: Bool {
        return false
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

这样设置后,只有AVP能响应旋转,底层的B和TabBar都会保持竖屏状态,从根源避免状态混乱。

额外说明

这个bug在iOS 11及以上版本已经被苹果官方修复了,如果你的应用最低支持版本可以升级到iOS 11,这个问题会自动消失。但如果必须兼容iOS 10,上面的方案都能有效解决底层弹窗异常的问题。

内容的提问来源于stack exchange,提问作者iur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:27:41