【iOS】ScreenRotator - 屏幕旋轉(zhuǎn)工具類 隨時(shí)隨地改變/保持屏幕方向

ScreenRotator

屏幕旋轉(zhuǎn)工具類,能通過代碼隨時(shí)隨地改變/保持屏幕方向。

Feature:
    ? 可控制旋轉(zhuǎn)三個(gè)方向:
        - 豎屏:手機(jī)頭在上邊
        - 橫屏:手機(jī)頭在左邊
        - 橫屏:手機(jī)頭在右邊
    ? 可控制是否隨手機(jī)擺動(dòng)自動(dòng)改變屏幕方向;
    ? 適配iOS16;
    ? 兼容 OC & Swift & SwiftUI;
    ? API簡(jiǎn)單易用。

Demo地址

使用效果

隨時(shí)隨地改變/保持屏幕方向
`push`或`present`一個(gè)跟當(dāng)前方向不一樣的新頁面
視頻的橫豎屏切換

使用前提

  1. 讓單例ScreenRotator.shared全局控制屏幕方向,首先得在AppDelegate中重寫:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return ScreenRotator.shared.orientationMask
}
  1. 不需要再重寫ViewControllersupportedInterfaceOrientationsshouldAutorotate

  2. 如需獲取屏幕實(shí)時(shí)尺寸,在對(duì)應(yīng)ViewController中重寫:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    // ??????:豎屏 --> 橫屏
    
    // 當(dāng)屏幕發(fā)生旋轉(zhuǎn)時(shí),系統(tǒng)會(huì)自動(dòng)觸發(fā)該函數(shù),`size`為【旋轉(zhuǎn)之后】的屏幕尺寸
    print("size \(size)") // --- (926.0, 428.0)
    // 或者通過`UIScreen`也能獲取【旋轉(zhuǎn)之后】的屏幕尺寸
    print("mainScreen \(UIScreen.main.bounds.size)") // --- (926.0, 428.0)

    // ?? 注意:如果想通過`self.xxx`去獲取屏幕相關(guān)的信息(如`self.view.frame`),【此時(shí)】獲取的尺寸還是【旋轉(zhuǎn)之前】的尺寸
    print("----------- 屏幕即將旋轉(zhuǎn) -----------")
    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)
    // ?? 想要獲取【旋轉(zhuǎn)之后】的屏幕信息,需要到`Runloop`的下一個(gè)循環(huán)才能獲取
    DispatchQueue.main.async {
        print("----------- 屏幕已經(jīng)旋轉(zhuǎn) -----------")
        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("==================================")
    }
}
  1. 如需監(jiān)聽屏幕的旋轉(zhuǎn),不用再監(jiān)聽UIDevice.orientationDidChangeNotification通知,而是監(jiān)聽該工具類提供的ScreenRotator.orientationDidChangeNotification通知?;蛘咄ㄟ^閉包的形式實(shí)現(xiàn)監(jiān)聽:
ScreenRotator.shard.orientationMaskDidChange = { orientationMask in 
    // 更新`FunnyButton`所屬`window`的方向
    FunnyButton.orientationMask = orientationMask
}

API

全局使用單例ScreenRotator.shared調(diào)用:

  1. 旋轉(zhuǎn)至目標(biāo)方向
func rotation(to orientation: Orientation)
  1. 旋轉(zhuǎn)至豎屏
func rotationToPortrait()
  1. 旋轉(zhuǎn)至橫屏(如果鎖定了屏幕,則轉(zhuǎn)向手機(jī)頭在左邊)
func rotationToLandscape()
  1. 旋轉(zhuǎn)至橫屏(手機(jī)頭在左邊)
func rotationToLandscapeLeft()
  1. 旋轉(zhuǎn)至橫屏(手機(jī)頭在右邊)
func rotationToLandscapeRight()
  1. 橫豎屏切換
func toggleOrientation()
  1. 是否正在豎屏
var isPortrait: Bool
  1. 當(dāng)前屏幕方向(ScreenRotator.Orientation)
var orientation: Orientation
  1. 是否鎖定屏幕方向(當(dāng)控制中心禁止了豎屏鎖定,為true則不會(huì)【隨手機(jī)擺動(dòng)自動(dòng)改變】屏幕方向)
var isLockOrientationWhenDeviceOrientationDidChange = true 
// PS:即便鎖定了(`true`)也能通過該工具類去旋轉(zhuǎn)屏幕方向
  1. 是否鎖定橫屏方向(當(dāng)控制中心禁止了豎屏鎖定,為true則【僅限橫屏的兩個(gè)方向會(huì)隨手機(jī)擺動(dòng)自動(dòng)改變】屏幕方向)
var isLockLandscapeWhenDeviceOrientationDidChange = false 
// PS:即便鎖定了(`true`)也能通過該工具類去旋轉(zhuǎn)屏幕方向
  1. 屏幕方向發(fā)生改變的回調(diào)
var orientationMaskDidChange: ((_ orientationMask: UIInterfaceOrientationMask) -> ())?
  1. 鎖定屏幕方向發(fā)生改變的回調(diào)
var lockOrientationWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?
  1. 鎖定橫屏方向發(fā)生改變的回調(diào)
var lockLandscapeWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?

可監(jiān)聽的通知

  1. 屏幕方向發(fā)生改變的通知:
  • ScreenRotator.orientationDidChangeNotification
    • object: orientationMask(UIInterfaceOrientationMask)
  1. 鎖定屏幕方向發(fā)生改變的通知:
  • ScreenRotator.lockOrientationWhenDeviceOrientationDidChangeNotification
    • object: isLockOrientationWhenDeviceOrientationDidChange(Bool)
  1. 鎖定橫屏方向發(fā)生改變的通知:
  • ScreenRotator.lockLandscapeWhenDeviceOrientationDidChangeNotification
    • object: isLockLandscapeWhenDeviceOrientationDidChange(Bool)

兼容 OC & SwiftUI

  • OC:使用專門用OC寫的JPScreenRotator,用法和ScreenRotator完全一致。

  • SwiftUI:可以通過ScreenRotatorState來更新狀態(tài)。

    • 具體使用可以參考Demo中的RotatorView。

Tips

當(dāng)pushpresent一個(gè)跟當(dāng)前方向不一樣的新頁面時(shí),建議先旋轉(zhuǎn),再延時(shí)至少0.1s才打開,否則新頁面的屏幕方向會(huì)錯(cuò)亂。例如:

let testVC = UIViewController()
// 1.先旋轉(zhuǎn)
ScreenRotator.shared.rotation(to: .landscapeRight)
// 2.延時(shí)至少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)
    }  
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容