ScreenRotator 0.1.1

ScreenRotator 0.1.1

RoguePing 维护。



  • 作者
  • Rogue24

ScreenRotator

一个实用类,允许在任何时间、任何地点旋转/锁定屏幕方向。

Features:
    ✅ Control rotation in three directions:
        - Portrait: Device held upright.
        - Landscape: Device rotated with the top towards the left.
        - Landscape: Device rotated with the top towards the right.
    ✅ Control whether screen orientation changes automatically with device movement.
    ✅ Compatible with iOS 16.
    ✅ Compatible with OC & Swift & SwiftUI.
    ✅ Simple and easy-to-use API.

用法示例

  • 在任意时间、任意地点旋转/锁定屏幕方向

ScreenRotator_1.gif

  • pushpresent 具有与当前方向不同的新页面

ScreenRotator_2.gif

  • 在视频中切换纵向和横向模式

ScreenRotator_3.gif

先决条件

  1. 要使用单例 ScreenRotator.shared 全局控制屏幕方向,请覆盖 AppDelegate 中的以下方法
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return ScreenRotator.shared.orientationMask
}
  1. 不再需要覆盖 supportedInterfaceOrientationsshouldAutorotateUIViewController 中。

  2. 如果您需要获取实时屏幕尺寸,请覆盖以下相应 ViewController 中的方法

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    // Implementation example provided in the document
}
  1. 如果您需要监听屏幕旋转,请使用此实用类提供的 ScreenRotator.orientationDidChangeNotification 通知或通过闭包实现
ScreenRotator.shared.orientationMaskDidChange = { orientationMask in 
    // Implementation example provided in the document
}

API

通过单例 ScreenRotator.shared 可用的方法

  1. 旋转到特定方向
func rotation(to orientation: Orientation)
  1. 旋转到纵向方向
func rotationToPortrait()
  1. 旋转到横向方向(禁用屏幕锁定时向上为左方)
func rotationToLandscape()
  1. 旋转到横向方向,顶部朝左
func rotationToLandscapeLeft()
  1. 旋转到横向方向,顶部朝右
func rotationToLandscapeRight()
  1. 在纵向和横向方向之间切换
func toggleOrientation()
  1. 检查设备是否处于纵向方向
var isPortrait: Bool
  1. 获取当前屏幕方向(ScreenRotator.Ordinal)
var orientation: Orientation
  1. 锁定/解锁根据设备旋转的屏幕方向更改
var isLockOrientationWhenDeviceOrientationDidChange: Bool 
  1. 锁定/解锁根据设备旋转的横向方向更改
var isLockLandscapeWhenDeviceOrientationDidChange: Bool 
  1. 用于处理屏幕方向变化的闭包
var orientationMaskDidChange: ((_ orientationMask: UIInterfaceOrientationMask) -> ())?
  1. 用于处理屏幕方向锁定状态变化的闭包
var lockOrientationWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?
  1. 用于处理横向方向锁定状态变化的闭包
var lockLandscapeWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?

可观察的通知

  1. 屏幕方向更改的通知
  • ScreenRotator.orientationDidChangeNotification
    • 对象:orientationMask (UIInterfaceOrientationMask)
  1. 屏幕方向锁定状态更改的通知
  • ScreenRotator.lockOrientationWhenDeviceOrientationDidChangeNotification
    • 对象:isLockOrientationWhenDeviceOrientationDidChange (Bool)
  1. 横向方向锁定状态更改的通知
  • ScreenRotator.lockLandscapeWhenDeviceOrientationDidChangeNotification
    • 对象:isLockLandscapeWhenDeviceOrientationDidChange (Bool)

兼容 OC & SwiftUI

  • Objective-C:使用专为 OC 编写的 JPScreenRotator,使用方法与 ScreenRotator 相同。

  • SwiftUI:使用 ScreenRotatorState 更新状态。

    • 有关详细信息,请参阅 Demo 中的 RotatorView

提示

当以不同方向推送或呈现新页面时,建议首先旋转,然后在至少 0.1 秒后打开,以避免屏幕方向混乱。示例

let testVC = UIViewController()

// 1. Rotate first
ScreenRotator.shared.rotation(to: .landscapeRight)

// 2. Open after a delay of at least 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)
    }  
}

安装

ScreenRotator 通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中即可

pod 'ScreenRotator'

中文说明

屏幕旋转工具类,可以通过代码随时随地旋转/锁定屏幕方向。

Feature:
    ✅ 可控制旋转三个方向:
        - 竖屏:手机头在上边
        - 横屏:手机头在左边
        - 横屏:手机头在右边
    ✅ 可控制是否随手机摆动自动改变屏幕方向;
    ✅ 适配iOS16;
    ✅ 兼容 OC & Swift & SwiftUI;
    ✅ API简单易用。

使用效果

  • 随时随地旋转/锁定屏幕方向

ScreenRotator_1.gif

  • pushpresent一个与当前方向不同的新页面

ScreenRotator_2.gif

  • 视频的横竖屏切换

ScreenRotator_3.gif

使用前提

  1. 要使单例ScreenRotator.shared全局控制屏幕方向,首先需要在AppDelegate中重写:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return ScreenRotator.shared.orientationMask
}
  1. 无需再重写UIViewControllersupportedInterfaceOrientationsshouldAutorotate

  2. 如需获取屏幕实时尺寸,在对应的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("==================================")
    }
}
  1. 如需监听屏幕的旋转,无需再监听UIDevice.orientationDidChangeNotification通知,而是监听该工具类提供的ScreenRotator.orientationDidChangeNotification通知。或者可以通过闭包的形式实现监听:
ScreenRotator.shard.orientationMaskDidChange = { orientationMask in 
    // 更新`FunnyButton`所属`window`的方向
    FunnyButton.orientationMask = orientationMask
}

API

全局使用单例ScreenRotator.shared进行调用:

  1. 旋转到目标方向
func rotation(to orientation: Orientation)
  1. 旋转到竖屏
func rotationToPortrait()
  1. 旋转到横屏(如果锁定了屏幕,则转向手机头在左边)
func rotationToLandscape()
  1. 旋转到横屏(手机头在左边)
func rotationToLandscapeLeft()
  1. 旋转到横屏(手机头在右边)
func rotationToLandscapeRight()
  1. 横竖屏切换
func toggleOrientation()
  1. 是否正在竖屏
var isPortrait: Bool
  1. 当前屏幕方向(ScreenRotator.Orientation)
var orientation: Orientation
  1. 是否锁定屏幕方向(当控制中心禁止竖屏锁定,为true时则不会随手机摆动自动改变屏幕方向)
var isLockOrientationWhenDeviceOrientationDidChange = true 
// PS:即便锁定了(`true`)也能通过该工具类去旋转屏幕方向
  1. 是否锁定横屏方向(当控制中心禁止竖屏锁定,为true时则仅限横屏的两个方向会随手机摆动自动改变屏幕方向)
var isLockLandscapeWhenDeviceOrientationDidChange = false 
// PS:即便锁定了(`true`)也能通过该工具类去旋转屏幕方向
  1. <屏幕方向>发生变化时的回调闭包
var orientationMaskDidChange: ((_ orientationMask: UIInterfaceOrientationMask) -> ())?
  1. <是否锁定屏幕方向>发生变化时的回调闭包
var lockOrientationWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?
  1. <是否锁定横屏方向>发生变化时的回调闭包
var lockLandscapeWhenDeviceOrientationDidChange: ((_ isLock: Bool) -> ())?

可监听的通知

  1. <屏幕方向>发生变化的通知:
  • ScreenRotator.orientationDidChangeNotification
    • object: orientationMask(UIInterfaceOrientationMask)
  1. <是否锁定屏幕方向>发生变化的通知:
  • ScreenRotator.lockOrientationWhenDeviceOrientationDidChangeNotification
    • object: isLockOrientationWhenDeviceOrientationDidChange(Bool)
  1. <是否锁定横屏方向>发生变化的通知:
  • ScreenRotator.lockLandscapeWhenDeviceOrientationDidChangeNotification
    • object: isLockLandscapeWhenDeviceOrientationDidChange(Bool)

兼容 Objective-C & SwiftUI

  • Objective-C:使用专门用 Objective-C 编写的 JPScreenRotator,用法与 ScreenRotator 完全一致。

  • SwiftUI:可以通过 ScreenRotatorState 来更新状态。

    • 具体使用可以参考 Demo 中的 RotatorView

提示

pushpresent 一个与当前方向不同的新页面时,建议先旋转,再延时至少 0.1 秒才打开,否则新页面的屏幕方向会错乱。例如:

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)
    }  
}

安装

ScreenRotator 可以通过 CocoaPods 安装,只需在你的 podfile 中添加以下行:

pod 'ScreenRotator'