You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS:固定竖屏的ViewController中如何让AV播放器随横屏切换全屏?

我之前做项目时刚好碰到过一模一样的需求,折腾了好一会儿才搞定,给你分享几个亲测有效的解决方案:

方案一:允许主VC支持横屏,但强制它始终显示竖屏

这个思路的核心是让主VC能接收到系统的旋转通知,同时限制它自身只能竖屏显示,这样内嵌的播放器就能正常响应横屏全屏的需求了。

步骤如下:

  1. 先在项目的「General -> Deployment Info」里,勾选所有你需要支持的屏幕方向(至少要包含竖屏和左右横屏)。
  2. 在主ViewController里重写旋转相关的属性,强制它只支持竖屏,但允许自动旋转:
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    // 固定主VC为竖屏
    return .portrait
}

override var shouldAutorotate: Bool {
    // 必须设为true,系统才会发送旋转通知
    return true
}
  1. 监听设备旋转通知,在主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有任何横屏的权限,那可以通过监听屏幕尺寸变化来间接判断设备是否旋转——毕竟横屏时屏幕的宽会大于高。

步骤如下:

  1. 在主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()
    }
}
  1. 自定义播放器全屏/退出的逻辑(如果用的不是系统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

火山引擎 最新活动