ScreenRotator
屏幕旋轉工具類,能通過代碼隨時隨地改變/保持屏幕方向。
Feature:
? 可控制旋轉三個方向:
- 豎屏:手機頭在上邊
- 橫屏:手機頭在左邊
- 橫屏:手機頭在右邊
? 可控制是否隨手機擺動自動改變屏幕方向;
? 適配iOS16;
? 兼容 OC & Swift & SwiftUI;
? API簡單易用。
使用效果
隨時隨地改變/保持屏幕方向
`push`或`present`一個跟當前方向不一樣的新頁面
視頻的橫豎屏切換
使用前提
- 讓單例
ScreenRotator.shared
全局控制屏幕方向,首先得在AppDelegate
中重寫:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return ScreenRotator.shared.orientationMask
}
不需要再重寫
ViewController
的supportedInterfaceOrientations
和shouldAutorotate
;如需獲取屏幕實時尺寸,在對應
ViewController
中重寫:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
// ??????:豎屏 --> 橫屏
// 當屏幕發生旋轉時,系統會自動觸發該函數,`size`為【旋轉之后】的屏幕尺寸
print("size \(size)") // --- (926.0, 428.0)
// 或者通過`UIScreen`也能獲取【旋轉之后】的屏幕尺寸
print("mainScreen \(UIScreen.main.bounds.size)") // --- (926.0, 428.0)
// ?? 注意:如果想通過`self.xxx`去獲取屏幕相關的信息(如`self.view.frame`),【此時】獲取的尺寸還是【旋轉之前】的尺寸
print("----------- 屏幕即將旋轉 -----------")
print("view.size \(view.frame.size)") // - (428.0, 926.0)
print("window.size \(view.window?.size ?? .zero)") // - (428.0, 926.0)
print("window.safeAreaInsets \(view.window?.safeAreaInsets ?? .zero)") // - UIEdgeInsets(top: 47.0, left: 0.0, bottom: 34.0, right: 0.0)
// ?? 想要獲取【旋轉之后】的屏幕信息,需要到`Runloop`的下一個循環才能獲取
DispatchQueue.main.async {
print("----------- 屏幕已經旋轉 -----------")
print("view.size \(self.view.frame.size)") // - (926.0, 428.0)
print("window.size \(self.view.window?.size ?? .zero)") // - (926.0, 428.0)
print("window.safeAreaInsets \(self.view.window?.safeAreaInsets ?? .zero)") // - UIEdgeInsets(top: 0.0, left: 47.0, bottom: 21.0, right: 47.0)
print("==================================")
}
}
- 如需監聽屏幕的旋轉,不用再監聽
UIDevice.orientationDidChangeNotification
通知,而是監聽該工具類提供的ScreenRotator.orientationDidChangeNotification
通知。或者通過閉包的形式實現監聽:
ScreenRotator.shard.orientationMaskDidChange = { orientationMask in
// 更新`FunnyButton`所屬`window`的方向
FunnyButton.orientationMask = orientationMask
}
API
全局使用單例ScreenRotator.shared
調用:
- 旋轉至目標方向
func rotation(to orientation: Orientation)
- 旋轉至豎屏
func rotationToPortrait()
- 旋轉至橫屏(如果鎖定了屏幕,則轉向手機頭在左邊)
func rotationToLandscape()
- 旋轉至橫屏(手機頭在左邊)
func rotationToLandscapeLeft()
- 旋轉至橫屏(手機頭在右邊)
func rotationToLandscapeRight()
- 橫豎屏切換
func toggleOrientation()
- 是否正在豎屏
var isPortrait: Bool
- 當前屏幕方向(ScreenRotator.Orientation)
var orientation: Orientation
- 是否鎖定屏幕方向(當控制中心禁止了豎屏鎖定,為
true
則不會【隨手機擺動自動改變】屏幕方向)
var isLockOrientationWhenDeviceOrientationDidChange = true
// PS:即便鎖定了(`true`)也能通過該工具類去旋轉屏幕方向
- 是否鎖定橫屏方向(當控制中心禁止了豎屏鎖定,為
true
則【僅限橫屏的兩個方向會隨手機擺動自動改變】屏幕方向)
var isLockLandscapeWhenDeviceOrientationDidChange = false
// PS:即便鎖定了(`true`)也能通過該工具類去旋轉屏幕方向
- 屏幕方向發生改變的回調
var orientationMaskDidChange: ((_ orientationMask: UIInterfaceOrientationMask) -> ())?
- 鎖定屏幕方向發生改變的回調
var lockOrientationWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?
- 鎖定橫屏方向發生改變的回調
var lockLandscapeWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?
可監聽的通知
- 屏幕方向發生改變的通知:
-
ScreenRotator.orientationDidChangeNotification
- object:
orientationMask
(UIInterfaceOrientationMask)
- object:
- 鎖定屏幕方向發生改變的通知:
-
ScreenRotator.lockOrientationWhenDeviceOrientationDidChangeNotification
- object:
isLockOrientationWhenDeviceOrientationDidChange
(Bool)
- object:
- 鎖定橫屏方向發生改變的通知:
-
ScreenRotator.lockLandscapeWhenDeviceOrientationDidChangeNotification
- object:
isLockLandscapeWhenDeviceOrientationDidChange
(Bool)
- object:
兼容 OC & SwiftUI
OC:使用專門用OC寫的
JPScreenRotator
,用法和ScreenRotator
完全一致。-
SwiftUI:可以通過
ScreenRotatorState
來更新狀態。- 具體使用可以參考Demo中的
RotatorView
。
- 具體使用可以參考Demo中的
Tips
當push
或present
一個跟當前方向不一樣的新頁面時,建議先旋轉,再延時至少0.1s才打開,否則新頁面的屏幕方向會錯亂。例如:
let testVC = UIViewController()
// 1.先旋轉
ScreenRotator.shared.rotation(to: .landscapeRight)
// 2.延時至少0.1s再打開
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
if let navCtr = self.navigationController {
navCtr.pushViewController(testVC, animated: true)
} else {
self.present(testVC, animated: true)
}
}