正文
我们公司的 app 只支持竖屏, 只有在视频播放的时候才可以横屏
, 所以这就需要我们强制去旋转屏幕. 我想一般的 app 大概都会有这种需求.
最近随着 iOS16
的更新, 线上的 app 在 iOS16
系统上不管用了, 原因就是苹果从 iOS16
开始, 更改了屏幕旋转的机制, 以后都要用 UIWindowScence
这个 API 类. 所以我们的 App 就只能根据版本去做适配, 新的要支持, 老的也要兼容.
在这里, 我就直接上干货, 只展示重要代码, 就不写 demo
, 没什么技术含量, 做为一个日常记录分享而已.
重点提示
Xcode 14.0
MacOS 12.5
手机 iOS15.1
和 iOS16
一. AppDelegate 配置
定义一个 bool 类型的变量
全局控制否是横屏代理方法根据这个变量来返回是 竖屏
还是 横屏
, iOS16
及以上可以做到根据屏幕方向适配横屏, 我们公司要求不高, 所以我们是强制右横屏, 这一点是不太友好, 这不是重点.
- 这一步
Swift
和ObjC
没什么区别, 只是语法不同, 所以就只提供了Swift
代码.
@main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? // 定义一个 bool 类型的变量 var isFullScreen: Bool = false func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { if isFullScreen { if #available(iOS 16.0, *) { // 16 及以上可以做到根据屏幕方向适配横屏 return .landscape } else { // 16 以下不方便做, 所以我们是强制 右横屏 return .landscapeRight } } return .portrait } }
二. 适配 iOS16 旋转屏幕
在原来基础上添加适配 iOS16
的代码 在 VC
中点击横屏按钮时进行强制屏幕旋转, 这里强调一下, 播放器的横屏按钮操作最好是回调到当前 VC 中去操作, setNeedsUpdateOfSupportedInterfaceOrientations()
这个方法是 VC 的对象方法, 这里同样Swift
和 ObjC
没什么区别, 只是语法不同.
func switchOrientation(isFullScreen: Bool) { let kAppdelegate = UIApplication.shared.delegate as? AppDelegate kAppdelegate?.isFullScreen = isFullScreen // 设置屏幕为横屏 if #available(iOS 16.0, *) { setNeedsUpdateOfSupportedInterfaceOrientations() guard let scence = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return } let orientation: UIInterfaceOrientationMask = isFullScreen ? .landscape : .portrait let geometryPreferencesIOS = UIWindowScene.GeometryPreferences.iOS(interfaceOrientations: orientation) scence.requestGeometryUpdate(geometryPreferencesIOS) { error in print("强制\(isFullScreen ? "横屏" : "竖屏" )错误: \(error)") } } else { let oriention: UIDeviceOrientation = isFullScreen ? .landscapeRight : .portrait UIDevice.current.setValue(oriention.rawValue, forKey: "orientation") UIViewController.attemptRotationToDeviceOrientation() } // 更新 横竖屏对应的 UI // ... }
三. 强制旋转屏幕
在播放器横竖屏切换按钮的回调方法中调用 旋转屏幕方法即可, 不管手机有没有打开自动旋转, 都可以实现屏幕方向切换.
// 播放器 - 全屏按钮切换回调 func playerViewRotateScreen(isFull: Bool) { switchOrientation(isFullScreen: isFull) }
四. 自动旋转
手机需要打开自动旋转开关, 注册屏幕旋转通知, 监听屏幕旋转时的方向. 方法不只一种, 但是我就用下面这个.
- 一定要注意下面这两个方法, 否则有可能通知不生效, 一个开启一个关闭.
- UIDevice.current.beginGeneratingDeviceOrientationNotifications()
- UIDevice.current.endGeneratingDeviceOrientationNotifications()
注意:
我这里做的是 16 以下只支持右横屏
, 16 不需要获取设备方向, 因此可以支持左/右
横屏. 这也是AppDelegate
中区分版本的原因.
友情提示 :
最好是把侧滑返回手势
给禁掉. 否则横屏侧滑返回就出问题了, 当然也可以做的更精细些, 横屏时禁止. 我做验证就简单些.
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) UIDevice.current.beginGeneratingDeviceOrientationNotifications() NotificationCenter.default.addObserver(self, selector: #selector(screenChangedOrientation(_:)), name: UIDevice.orientationDidChangeNotification, object: nil) navigationController?.interactivePopGestureRecognizer?.isEnabled = false } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) navigationController?.interactivePopGestureRecognizer?.isEnabled = true } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) NotificationCenter.default.removeObserver(self) UIDevice.current.endGeneratingDeviceOrientationNotifications() } // 横竖屏监听 @objc private func screenChangedOrientation(_ notification: Notification) { let info = notification.userInfo guard let animated = info?["UIDeviceOrientationRotateAnimatedUserInfoKey"] as? Int, animated == 1 else { return } let orientation = UIDevice.current.orientation if orientation == UIDeviceOrientation.landscapeLeft || orientation == UIDeviceOrientation.landscapeRight { // 横屏 videoView.changeScreenOrientation(isFull: true) } else if orientation == UIDeviceOrientation.portrait { // 竖屏 videoView.changeScreenOrientation(isFull: false) } }
以上就是配置iOS 16 屏幕旋转适配实例详解的详细内容,更多关于iOS 16 屏幕旋转适配的资料请关注脚本之家其它相关文章!