OrientationLock.swift 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  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. func setDefaultSupportedInferfaceOrientations()
  12. }
  13. /// Use the `supportedInterfaceOrientations` modifier on a SwiftUI view to lock its orientation.
  14. /// To function, `OrientationLock.deviceOrientationController` must be assigned prior to use.
  15. public final class OrientationLock {
  16. /// The global controller for device orientation.
  17. /// The property must be assigned prior to instantiating any OrientationLock.
  18. public static weak var deviceOrientationController: DeviceOrientationController?
  19. fileprivate init(_ supportedInterfaceOrientations: UIInterfaceOrientationMask) {
  20. guard let deviceOrientationController = Self.deviceOrientationController else {
  21. assertionFailure("OrientationLock.deviceOrientationController must be assigned prior to constructing an OrientationLock")
  22. return
  23. }
  24. deviceOrientationController.supportedInterfaceOrientations = supportedInterfaceOrientations
  25. }
  26. func setDefaultSupportedInferfaceOrientations() {
  27. Self.deviceOrientationController?.setDefaultSupportedInferfaceOrientations()
  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. // when view disappears, it reverts to the originally support orientations
  46. var body: some View {
  47. content
  48. .onDisappear { orientationLock.setDefaultSupportedInferfaceOrientations() }
  49. }
  50. }