11//
2- // ScanKit .swift
2+ // UIScanKitPreview .swift
33// SwiftUI ScanKit
44//
55// Copyright © 2023 Shawn Davis
@@ -41,26 +41,18 @@ public struct ScanKitPreview: UIViewControllerRepresentable {
4141 self . camera = camera
4242 }
4343
44- public func makeUIViewController( context: Context ) -> UICodeScanner {
45- return UICodeScanner ( camera: camera)
44+ public func makeUIViewController( context: Context ) -> UIScanKitPreview {
45+ return UIScanKitPreview ( camera: camera)
4646 }
4747
48- public func updateUIViewController( _ uiViewController: UICodeScanner , context: Context ) {
49- // Do nothing!
48+ public func updateUIViewController( _ uiViewController: UIScanKitPreview , context: Context ) {
49+ // Do nothing
5050 }
5151}
5252
53- public class UICodeScanner : UIViewController {
53+ public class UIScanKitPreview : UIViewController {
5454 weak var camera : ScanKitCamera ?
5555
56- private var deviceOrientation : UIDeviceOrientation {
57- var orientation = UIDevice . current. orientation
58- if orientation == UIDeviceOrientation . unknown {
59- orientation = . portrait
60- }
61- return orientation
62- }
63-
6456 init ( camera: ScanKitCamera ) {
6557 self . camera = camera
6658 super. init ( nibName: nil , bundle: nil )
@@ -70,20 +62,28 @@ public class UICodeScanner: UIViewController {
7062 fatalError ( " init(coder:) has not been implemented " )
7163 }
7264
73- public override func viewDidLoad( ) {
74- super. viewDidLoad ( )
65+ public override func viewWillAppear( _ animated: Bool ) {
66+ super. viewWillAppear ( animated)
67+ UIDevice . current. beginGeneratingDeviceOrientationNotifications ( )
68+
69+ CATransaction . begin ( )
70+ CATransaction . setDisableActions ( true )
7571 addPreviewLayer ( )
76- }
77-
78- public override func viewDidAppear( _ animated: Bool ) {
72+ CATransaction . commit ( )
73+
7974 // Start the camera
80- Task . detached ( priority: . userInitiated) { [ weak self] in
75+ Task ( priority: . userInitiated) { [ weak self] in
8176 await self ? . camera? . start ( )
8277 }
8378 }
8479
80+ public override func viewDidAppear( _ animated: Bool ) {
81+ super. viewDidAppear ( animated)
82+ }
83+
8584 public override func viewWillDisappear( _ animated: Bool ) {
8685 super. viewWillDisappear ( animated)
86+ UIDevice . current. endGeneratingDeviceOrientationNotifications ( )
8787 camera? . stop ( )
8888 }
8989
@@ -93,25 +93,56 @@ public class UICodeScanner: UIViewController {
9393 // Update video orientation on rotate
9494 guard let connection = camera? . previewLayer. connection else { return }
9595 if connection. isVideoOrientationSupported {
96- connection. videoOrientation = videoOrientation ( for: deviceOrientation)
96+ print ( " updating orientation... " )
97+ Task { @MainActor in
98+ connection. videoOrientation = appropriateVideoOrientation
99+ }
97100 }
98101
102+ CATransaction . begin ( )
103+ CATransaction . setDisableActions ( true )
99104 self . camera? . previewLayer. frame = self . view. bounds
105+ CATransaction . commit ( )
100106 }
101107
102108 private func addPreviewLayer( ) {
103109 if let previewLayer = self . camera? . previewLayer {
110+ previewLayer. frame = self . view. bounds
104111 self . view. layer. addSublayer ( previewLayer)
105112 }
106113 }
107114
115+ private var appropriateVideoOrientation : AVCaptureVideoOrientation {
116+ let orientation = UIDevice . current. orientation
117+
118+ // If the device orientation cannot be found, check the UI instead...
119+ if orientation == . unknown {
120+ return videOrientationFromInterfaceOrientation ( self . preferredInterfaceOrientationForPresentation)
121+ }
122+ return videoOrientationFromDeviceOrientation ( orientation)
123+ }
124+
125+ /// Converts a `UIInterfaceOrientation` to an appropriate `AVCaptureVideoOrientation` equivalent.
126+ private func videOrientationFromInterfaceOrientation( _ interfaceOrientation: UIInterfaceOrientation ) -> AVCaptureVideoOrientation {
127+ switch interfaceOrientation {
128+ case . unknown: return . portrait
129+ case . portrait: return . portrait
130+ case . portraitUpsideDown: return . portrait
131+ case . landscapeLeft: return . landscapeLeft
132+ case . landscapeRight: return . landscapeRight
133+ default : return . portrait
134+ }
135+ }
136+
108137 /// Converts a `UIDeviceOrientation` to an appropriate `AVCaptureVideoOrientation` equivalent.
109- private func videoOrientation ( for deviceOrientation: UIDeviceOrientation ) -> AVCaptureVideoOrientation {
138+ private func videoOrientationFromDeviceOrientation ( _ deviceOrientation: UIDeviceOrientation ) -> AVCaptureVideoOrientation {
110139 switch deviceOrientation {
111- case . portrait: return AVCaptureVideoOrientation . portrait
112- case . portraitUpsideDown: return AVCaptureVideoOrientation . portraitUpsideDown
113- case . landscapeLeft: return AVCaptureVideoOrientation . landscapeRight
114- case . landscapeRight: return AVCaptureVideoOrientation . landscapeLeft
140+ case . portrait: return . portrait
141+ case . portraitUpsideDown: return . portraitUpsideDown
142+ case . landscapeLeft: return . landscapeRight
143+ case . landscapeRight: return . landscapeLeft
144+ case . faceUp: return . landscapeRight
145+ case . faceDown: return . landscapeRight
115146 default : return . portrait
116147 }
117148 }
0 commit comments