iOS:固定竖屏的ViewController中如何让AV播放器随横屏切换全屏?
我之前做项目时刚好碰到过一模一样的需求,折腾了好一会儿才搞定,给你分享几个亲测有效的解决方案:
方案一:允许主VC支持横屏,但强制它始终显示竖屏
这个思路的核心是让主VC能接收到系统的旋转通知,同时限制它自身只能竖屏显示,这样内嵌的播放器就能正常响应横屏全屏的需求了。
步骤如下:
- 先在项目的「General -> Deployment Info」里,勾选所有你需要支持的屏幕方向(至少要包含竖屏和左右横屏)。
- 在主ViewController里重写旋转相关的属性,强制它只支持竖屏,但允许自动旋转:
override var supportedInterfaceOrientations: UIInterfaceOrientationMask { // 固定主VC为竖屏 return .portrait } override var shouldAutorotate: Bool { // 必须设为true,系统才会发送旋转通知 return true }
- 监听设备旋转通知,在主VC里处理播放器的全屏逻辑:
override func viewDidLoad() { super.viewDidLoad() // 注册设备方向变化通知 NotificationCenter.default.addObserver( self, selector: #selector(handleOrientationChange), name: UIDevice.orientationDidChangeNotification, object: nil ) } @objc private func handleOrientationChange() { let currentOrientation = UIDevice.current.orientation // 排除未知、FaceDown等无效状态,只判断横屏/竖屏 if currentOrientation.isLandscape { // 让AVPlayerViewController进入全屏 yourPlayerVC.enterFullScreen(animated: true) } else if currentOrientation.isPortrait { // 退出全屏 yourPlayerVC.exitFullScreen(animated: true) } } // 记得在销毁时移除通知 deinit { NotificationCenter.default.removeObserver(self) }
方案二:不修改主VC旋转权限,用屏幕边界变化间接检测旋转
如果不想让主VC有任何横屏的权限,那可以通过监听屏幕尺寸变化来间接判断设备是否旋转——毕竟横屏时屏幕的宽会大于高。
步骤如下:
- 在主VC的viewDidLoad里添加屏幕边界变化的监听:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver( self, selector: #selector(handleScreenBoundsChange), name: UIScreen.boundsDidChangeNotification, object: nil ) } @objc private func handleScreenBoundsChange() { let screenSize = UIScreen.main.bounds.size if screenSize.width > screenSize.height { // 横屏状态,触发播放器全屏 showPlayerFullScreen() } else { // 竖屏状态,退出全屏 dismissPlayerFullScreen() } }
- 自定义播放器全屏/退出的逻辑(如果用的不是系统AVPlayerViewController的话):
private func showPlayerFullScreen() { // 把播放器view移到window上,设置全屏frame if let window = UIApplication.shared.windows.first { yourPlayerView.frame = window.bounds window.addSubview(yourPlayerView) // 可以添加动画效果 UIView.animate(withDuration: 0.3) { yourPlayerView.alpha = 1 } } } private func dismissPlayerFullScreen() { // 把播放器view移回主VC的原位置 UIView.animate(withDuration: 0.3) { yourPlayerView.frame = self.playerContainerView.bounds } completion: { _ in self.playerContainerView.addSubview(self.yourPlayerView) } }
额外适配iOS 16+的注意点
如果你的APP是基于场景(Scene)的架构,还要在SceneDelegate里处理方向权限,确保播放器全屏时能支持横屏:
func windowScene(_ windowScene: UIWindowScene, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { // 获取当前最上层的ViewController guard let topVC = window?.rootViewController?.topMostViewController else { return .portrait } // 如果当前是播放器VC,允许横屏;否则固定竖屏 if topVC is AVPlayerViewController { return .allButUpsideDown } else { return .portrait } } // 给UIViewController加个扩展,方便获取最上层VC extension UIViewController { var topMostViewController: UIViewController { if let presentedVC = presentedViewController { return presentedVC.topMostViewController } return self } }
内容的提问来源于stack exchange,提问作者Nagendra Rao




