OrientationLock.swift 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. //
  2. // OrientationLock.swift
  3. // LoopKitUI
  4. //
  5. // Created by Michael Pangburn on 7/28/20.
  6. // Copyright © 2020 LoopKit Authors. All rights reserved.
  7. //
  8. import SwiftUI
  9. public protocol DeviceOrientationController: AnyObject {
  10. var supportedInterfaceOrientations: UIInterfaceOrientationMask { get set }
  11. }
  12. /// A class whose lifetime defines the application's supported interface orientations.
  13. ///
  14. /// Use the `supportedInterfaceOrientations` modifier on a SwiftUI view to lock its orientation.
  15. /// To function, `OrientationLock.deviceOrientationController` must be assigned prior to use.
  16. public final class OrientationLock {
  17. private let originalSupportedInterfaceOrientations: UIInterfaceOrientationMask
  18. /// The global controller for device orientation.
  19. /// The property must be assigned prior to instantiating any OrientationLock.
  20. public static weak var deviceOrientationController: DeviceOrientationController?
  21. fileprivate init(_ supportedInterfaceOrientations: UIInterfaceOrientationMask) {
  22. assert(Self.deviceOrientationController != nil, "OrientationLock.deviceOrientationController must be assigned prior to constructing an OrientationLock")
  23. originalSupportedInterfaceOrientations = Self.deviceOrientationController?.supportedInterfaceOrientations ?? .allButUpsideDown
  24. Self.deviceOrientationController?.supportedInterfaceOrientations = supportedInterfaceOrientations
  25. }
  26. deinit {
  27. Self.deviceOrientationController?.supportedInterfaceOrientations = originalSupportedInterfaceOrientations
  28. }
  29. }
  30. extension View {
  31. /// Use the `supportedInterfaceOrientations` modifier on a SwiftUI view to lock its orientation.
  32. /// To function, `OrientationLock.deviceOrientationController` must be assigned prior to use.
  33. public func supportedInterfaceOrientations(_ supportedInterfaceOrientations: UIInterfaceOrientationMask) -> some View {
  34. OrientationLocked(supportedInterfaceOrientations: supportedInterfaceOrientations, content: self)
  35. }
  36. }
  37. private struct OrientationLocked<Content: View>: View {
  38. // Annotated with `@State` to ensure SwiftUI keeps the object alive for the duration of the view's lifetime
  39. @State var orientationLock: OrientationLock
  40. var content: Content
  41. init(supportedInterfaceOrientations: UIInterfaceOrientationMask, content: Content) {
  42. self._orientationLock = State(wrappedValue: OrientationLock(supportedInterfaceOrientations))
  43. self.content = content
  44. }
  45. var body: some View { content }
  46. }