Skip to content

Instantly share code, notes, and snippets.

@HarryGoodwin
Last active November 27, 2024 10:51
Show Gist options
  • Save HarryGoodwin/414902bda35f66eeb3a1d424273ec057 to your computer and use it in GitHub Desktop.
Save HarryGoodwin/414902bda35f66eeb3a1d424273ec057 to your computer and use it in GitHub Desktop.
Detecting Device Rotation In Swift
import UIKit
import SwiftUI
@MainActor
@Observable
public final class OrientationMonitor {
public enum RotationDirection: String {
case anticlockwise
case clockwise
case unknown
}
public private(set) var current: UIDeviceOrientation
public private(set) var lastRotation: RotationDirection
public init() {
current = UIDevice.current.orientation
lastRotation = .unknown
Task {
for await notification in NotificationCenter.default.notifications(named: UIDevice.orientationDidChangeNotification) {
guard let device = notification.object as? UIDevice else { return }
let newOrientation = device.orientation
let direction = calculateRotationDirection(
newOrientation: newOrientation,
currentOrientation: current
)
current = newOrientation
lastRotation = direction
}
}
}
private func calculateRotationDirection(
newOrientation: UIDeviceOrientation,
currentOrientation: UIDeviceOrientation
) -> RotationDirection {
var direction: RotationDirection = .unknown
switch newOrientation {
case .unknown:
return .unknown
case .portrait:
switch currentOrientation {
case .portrait:
direction = .unknown
case .portraitUpsideDown:
direction = .unknown
case .landscapeLeft:
direction = .clockwise
case .landscapeRight:
direction = .anticlockwise
case .unknown, .faceUp, .faceDown:
direction = .unknown
@unknown default:
direction = .unknown
}
case .portraitUpsideDown:
switch currentOrientation {
case .portrait:
direction = .unknown
case .portraitUpsideDown:
direction = .unknown
case .landscapeLeft:
direction = .anticlockwise
case .landscapeRight:
direction = .clockwise
case .unknown, .faceUp, .faceDown:
direction = .unknown
@unknown default:
direction = .unknown
}
case .landscapeLeft:
switch currentOrientation {
case .portrait:
direction = .anticlockwise
case .portraitUpsideDown:
direction = .clockwise
case .landscapeLeft:
direction = .unknown
case .landscapeRight:
direction = .unknown
case .unknown, .faceUp, .faceDown:
direction = .unknown
@unknown default:
direction = .unknown
}
case .landscapeRight:
switch currentOrientation {
case .portrait:
direction = .clockwise
case .portraitUpsideDown:
direction = .anticlockwise
case .landscapeLeft:
direction = .unknown
case .landscapeRight:
direction = .unknown
case .unknown, .faceUp, .faceDown:
direction = .unknown
@unknown default:
direction = .unknown
}
case .faceDown, .faceUp:
break
@unknown default:
break
}
return direction
}
}
/// This is not needed for operation, just for a text representation of the
/// orientation in the demo.
extension UIDeviceOrientation {
var displayValue: String {
switch self {
case .unknown:
"unknown"
case .portrait:
"portrait"
case .portraitUpsideDown:
"portraitUpsideDown"
case .landscapeLeft:
"landscapeLeft"
case .landscapeRight:
"landscapeRight"
case .faceUp:
"faceUp"
case .faceDown:
"faceDown"
@unknown default:
"unknown"
}
}
}
/// Test View
struct OrientationView: View {
@State var orientation = OrientationMonitor()
var body: some View {
VStack {
Text(orientation.current.displayValue)
Text(orientation.lastRotation.rawValue)
}
.padding()
}
}
#Preview {
OrientationView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment