Objective-C中如何在禁止旋转的ViewController内检测设备真实朝向
固定竖屏ViewController检测设备真实朝向方案
核心逻辑
不要使用UIKit提供的UIInterfaceOrientation系列属性(包含ViewController的interfaceOrientation、状态栏朝向等),这类属性返回的是当前页面的显示朝向,锁竖屏后不会随设备转动变化。你需要监听设备的物理朝向,通过UIDeviceOrientation相关接口实现即可。
实现步骤
1. 开启设备朝向通知监听
默认设备朝向变更通知处于关闭状态,需要主动开启并注册监听:
// Swift 示例 // 开启设备朝向更新 UIDevice.current.beginGeneratingDeviceOrientationNotifications() // 注册朝向变化通知 NotificationCenter.default.addObserver( self, selector: #selector(onDeviceOrientationChanged), name: UIDevice.orientationDidChangeNotification, object: nil )
// Objective-C 示例 [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDeviceOrientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
2. 实现朝向变更回调函数
在回调中可以直接获取当前设备的真实物理朝向,执行对应的业务逻辑即可:
@objc private func onDeviceOrientationChanged() { let currentOrientation = UIDevice.current.orientation switch currentOrientation { case .portrait: // 设备正立竖屏逻辑 case .portraitUpsideDown: // 设备倒立竖屏逻辑 case .landscapeLeft: // 设备左横屏逻辑(物理朝向为设备向左旋转) case .landscapeRight: // 设备右横屏逻辑(物理朝向为设备向右旋转) case .faceUp, .faceDown: // 设备平放朝上/朝下逻辑,不需要可忽略 default: // 未知朝向兜底逻辑 break } }
3. 页面销毁时清理资源
避免内存泄漏,页面销毁时需移除通知、关闭朝向更新:
// Swift 示例,写在deinit方法中 deinit { NotificationCenter.default.removeObserver( self, name: UIDevice.orientationDidChangeNotification, object: nil ) UIDevice.current.endGeneratingDeviceOrientationNotifications() }
// Objective-C 示例,写在dealloc方法中 - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; }
特殊场景适配
如果需要在设备平放时也能精准判断朝向,或者需要更高的检测频率,可以用CoreMotion框架读取加速度计数据自行计算朝向:
import CoreMotion private let motionManager = CMMotionManager() // 开启加速度计监听 private func startMotionDetection() { guard motionManager.isAccelerometerAvailable else { return } motionManager.accelerometerUpdateInterval = 0.2 // 每0.2秒更新一次 motionManager.startAccelerometerUpdates(to: .main) { [weak self] data, error in guard let data = data, error == nil else { return } // 通过加速度的x、y轴数值判断朝向,示例逻辑: let x = data.acceleration.x let y = data.acceleration.y if abs(x) > abs(y) { if x > 0 { // 设备右横屏 } else { // 设备左横屏 } } else { if y > 0 { // 设备倒立竖屏 } else { // 设备正立竖屏 } } } } // 销毁时停止运动检测 deinit { motionManager.stopAccelerometerUpdates() }
内容的提问来源于stack exchange,提问作者Vinh Hung Nguyen
相关产品推荐
相关产品推荐

