1
1
//
2
- // ScanKit .swift
2
+ // UIScanKitPreview .swift
3
3
// SwiftUI ScanKit
4
4
//
5
5
// Copyright © 2023 Shawn Davis
@@ -41,26 +41,18 @@ public struct ScanKitPreview: UIViewControllerRepresentable {
41
41
self . camera = camera
42
42
}
43
43
44
- public func makeUIViewController( context: Context ) -> UICodeScanner {
45
- return UICodeScanner ( camera: camera)
44
+ public func makeUIViewController( context: Context ) -> UIScanKitPreview {
45
+ return UIScanKitPreview ( camera: camera)
46
46
}
47
47
48
- public func updateUIViewController( _ uiViewController: UICodeScanner , context: Context ) {
49
- // Do nothing!
48
+ public func updateUIViewController( _ uiViewController: UIScanKitPreview , context: Context ) {
49
+ // Do nothing
50
50
}
51
51
}
52
52
53
- public class UICodeScanner : UIViewController {
53
+ public class UIScanKitPreview : UIViewController {
54
54
weak var camera : ScanKitCamera ?
55
55
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
-
64
56
init ( camera: ScanKitCamera ) {
65
57
self . camera = camera
66
58
super. init ( nibName: nil , bundle: nil )
@@ -70,20 +62,28 @@ public class UICodeScanner: UIViewController {
70
62
fatalError ( " init(coder:) has not been implemented " )
71
63
}
72
64
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 )
75
71
addPreviewLayer ( )
76
- }
77
-
78
- public override func viewDidAppear( _ animated: Bool ) {
72
+ CATransaction . commit ( )
73
+
79
74
// Start the camera
80
- Task . detached ( priority: . userInitiated) { [ weak self] in
75
+ Task ( priority: . userInitiated) { [ weak self] in
81
76
await self ? . camera? . start ( )
82
77
}
83
78
}
84
79
80
+ public override func viewDidAppear( _ animated: Bool ) {
81
+ super. viewDidAppear ( animated)
82
+ }
83
+
85
84
public override func viewWillDisappear( _ animated: Bool ) {
86
85
super. viewWillDisappear ( animated)
86
+ UIDevice . current. endGeneratingDeviceOrientationNotifications ( )
87
87
camera? . stop ( )
88
88
}
89
89
@@ -93,25 +93,56 @@ public class UICodeScanner: UIViewController {
93
93
// Update video orientation on rotate
94
94
guard let connection = camera? . previewLayer. connection else { return }
95
95
if connection. isVideoOrientationSupported {
96
- connection. videoOrientation = videoOrientation ( for: deviceOrientation)
96
+ print ( " updating orientation... " )
97
+ Task { @MainActor in
98
+ connection. videoOrientation = appropriateVideoOrientation
99
+ }
97
100
}
98
101
102
+ CATransaction . begin ( )
103
+ CATransaction . setDisableActions ( true )
99
104
self . camera? . previewLayer. frame = self . view. bounds
105
+ CATransaction . commit ( )
100
106
}
101
107
102
108
private func addPreviewLayer( ) {
103
109
if let previewLayer = self . camera? . previewLayer {
110
+ previewLayer. frame = self . view. bounds
104
111
self . view. layer. addSublayer ( previewLayer)
105
112
}
106
113
}
107
114
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
+
108
137
/// Converts a `UIDeviceOrientation` to an appropriate `AVCaptureVideoOrientation` equivalent.
109
- private func videoOrientation ( for deviceOrientation: UIDeviceOrientation ) -> AVCaptureVideoOrientation {
138
+ private func videoOrientationFromDeviceOrientation ( _ deviceOrientation: UIDeviceOrientation ) -> AVCaptureVideoOrientation {
110
139
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
115
146
default : return . portrait
116
147
}
117
148
}
0 commit comments