Skip to content

Instantly share code, notes, and snippets.

@PabloDomine
Last active August 5, 2022 06:41
Show Gist options
  • Save PabloDomine/a3fbb869cc2652080afd5f4af9644767 to your computer and use it in GitHub Desktop.
Save PabloDomine/a3fbb869cc2652080afd5f4af9644767 to your computer and use it in GitHub Desktop.
Class that determines Device Orientation based on the accelerometer motion data readouts
import Foundation
import CoreMotion
class DeviceOrientationHelper {
static let shared = DeviceOrientationHelper() // Singleton is recommended because an app should create only a single instance of the CMMotionManager class.
private let motionManager: CMMotionManager
private let queue: OperationQueue
typealias DeviceOrientationHandler = ((_ deviceOrientation: UIDeviceOrientation) -> Void)?
private var deviceOrientationAction: DeviceOrientationHandler?
public var currentDeviceOrientation: UIDeviceOrientation = .portrait
private let motionLimit: Double = 0.6 // Smallers values makes it much sensitive to detect an orientation change. [0 to 1]
init() {
motionManager = CMMotionManager()
motionManager.accelerometerUpdateInterval = 0.2 // Specify an update interval in seconds, personally found this value provides a good UX
queue = OperationQueue()
}
public func startDeviceOrientationNotifier(with handler: DeviceOrientationHandler) {
self.deviceOrientationAction = handler
// Using main queue is not recommended. So create new operation queue and pass it to startAccelerometerUpdatesToQueue.
// Dispatch U/I code to main thread using dispach_async in the handler.
motionManager.startAccelerometerUpdates(to: queue) { (data, error) in
if let accelerometerData = data {
var newDeviceOrientation: UIDeviceOrientation?
if (accelerometerData.acceleration.x >= self.motionLimit) {
newDeviceOrientation = .landscapeLeft
}
else if (accelerometerData.acceleration.x <= -self.motionLimit) {
newDeviceOrientation = .landscapeRight
}
else if (accelerometerData.acceleration.y <= -self.motionLimit) {
newDeviceOrientation = .portrait
}
else if (accelerometerData.acceleration.y >= self.motionLimit) {
newDeviceOrientation = .portraitUpsideDown
}
else {
return
}
// Only if a different orientation is detect, execute handler
if newDeviceOrientation != self.currentDeviceOrientation {
self.currentDeviceOrientation = newDeviceOrientation
if let deviceOrientationHandler = self.deviceOrientationAction {
DispatchQueue.main.async {
deviceOrientationHandler!(self.currentDeviceOrientation)
}
}
}
}
}
}
public func stopDeviceOrientationNotifier() {
motionManager.stopAccelerometerUpdates()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment