咱们公司的 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)
}
}