@@ -30,6 +30,9 @@ struct OSBARCScannerView: View {
3030 /// The type of device being used.
3131 let deviceType : OSBARCDeviceTypeModel
3232
33+ /// Frame of portion of the screen used for scanning.
34+ @State var scanFrame : CGRect = . zero
35+
3336 /// The horizontal visual size available.
3437 @Environment ( \. horizontalSizeClass) private var horizontalSizeClass
3538 /// The vertical visual size available.
@@ -46,20 +49,9 @@ struct OSBARCScannerView: View {
4649 /// The spacing between the buttons (used on iPads and iPhones on Landscape mode).
4750 private let buttonSpacing : CGFloat = OSBARCScannerViewConfigurationValues . buttonSpacing
4851
49- /// Draws the background view (black with a little transparency).
50- /// - Parameters:
51- /// - height: The height to use, if any.
52- /// - width: The width to use, if any.
53- /// - Returns: Returns the view to display.
54- @ViewBuilder
55- private func backgroundView( height: CGFloat ? = nil , width: CGFloat ? = nil ) -> some View {
56- OSBARCScannerViewConfigurationValues . backgroundColour
57- . if ( height != nil ) {
58- $0. frame ( height: height ?? 0.0 ) // the fallback value will never be executed
59- }
60- . if ( width != nil ) {
61- $0. frame ( width: width ?? 0.0 ) // the fallback value will never be executed
62- }
52+ /// View filled with the background colour
53+ private var backgroundView : OSBARCBackgroundView {
54+ . init( scanFrame: scanFrame)
6355 }
6456
6557 /// Cancel button.
@@ -91,12 +83,22 @@ struct OSBARCScannerView: View {
9183 private func scanningZone( for size: CGSize ) -> some View {
9284 let scannerSize : CGSize = calculateSize ( for: size)
9385
94- ZStack ( alignment: . topLeading) {
95- // inner background view
96- OSBARCBackgroundView ( padding: scannerPadding, size: scannerSize)
97-
98- // Scanning Zone
86+ // Scanning Zone
87+ GeometryReader { scanningZoneProxy in
9988 OSBARCScanningZone ( size: scannerSize)
89+ . onAppear ( perform: {
90+ let scanningZoneFrame = scanningZoneProxy. frame ( in: . global)
91+ scanFrame = . init(
92+ x: scanningZoneFrame. minX + scannerPadding,
93+ y: scanningZoneFrame. minY + scannerPadding,
94+ width: scanningZoneFrame. width - 2.0 * scannerPadding,
95+ height: scanningZoneFrame. height - 2.0 * scannerPadding
96+ )
97+ } )
98+ . valueChanged ( value: scanFrame) {
99+ // everytime `scanFrame` changes, the notification is triggered so that the barcode detection region gets updated.
100+ NotificationCenter . default. post ( name: . scanFrameChanged, object: $0)
101+ }
100102 }
101103 . frame ( width: scannerSize. width, height: scannerSize. height)
102104 }
@@ -108,8 +110,6 @@ struct OSBARCScannerView: View {
108110 // Scan Instructions
109111 instructionsTextField
110112
111- backgroundView ( height: scannerPadding)
112-
113113 GeometryReader {
114114 scanningZone ( for: $0. size)
115115 }
@@ -126,115 +126,96 @@ struct OSBARCScannerView: View {
126126
127127 // MARK: - Main Element
128128 var body : some View {
129- ZStack ( alignment : . topLeading ) {
129+ ZStack {
130130 // Camera Stream
131131 OSBARCScannerViewControllerRepresentable ( captureDevice, $scanResult, shouldShowButton, $buttonScanEnabled, orientationModel)
132132
133- // Background Black View
134- GeometryReader { proxy in
135- OSBARCBackgroundView ( padding: screenPadding, size: proxy. size)
136- }
133+ backgroundView
137134
138135 if isPhoneInPortrait {
139- VStack ( spacing: 0.0 ) {
136+ VStack ( spacing: screenPadding ) {
140137 // X View
141- ZStack {
142- backgroundView ( )
138+ HStack {
139+ Spacer ( )
143140
144- HStack {
145- Spacer ( )
146-
147- // Cancel Button
148- cancelButton
149- }
141+ // Cancel Button
142+ cancelButton
150143 }
151144
152- backgroundView ( height: screenPadding)
153-
154145 GeometryReader { scannerProxy in
155- VStack ( spacing: 0.0 ) {
156- backgroundView ( )
157-
146+ VStack ( spacing: screenPadding) {
158147 // Scan Instructions
159148 instructionsTextField
160-
161- backgroundView ( height: screenPadding)
162-
149+ // Scanning Zone
163150 scanningZone ( for: scannerProxy. size)
164-
165- backgroundView ( )
166151 }
152+ . frame ( maxHeight: . infinity, alignment: . center)
167153 }
168- . layoutPriority ( 1 )
169-
170- backgroundView ( height: screenPadding)
171154
172155 // Buttons View
173- ZStack {
174- backgroundView ( )
175-
176- ZStack ( alignment: . trailing) {
177- // Scan Button
178- scanButton
156+ ZStack ( alignment: . trailing) {
157+ // Scan Button
158+ scanButton
179159 . opacity ( !shouldShowButton ? 0.0 : 1.0 )
180160 . disabled ( !shouldShowButton)
181161 . frame ( maxWidth: . infinity)
182-
183- // Torch Button
184- torchButton
162+
163+ // Torch Button
164+ torchButton
185165 . opacity ( !cameraHasTorch ? 0.0 : 1.0 )
186- . disabled ( !cameraHasTorch)
187- }
166+ . disabled ( !cameraHasTorch)
188167 }
189168 }
190169 . padding ( screenPadding)
191170 } else {
192171 GeometryReader { mainProxy in
193- HStack ( spacing: 0.0 ) {
194- backgroundView ( )
172+ HStack ( spacing: scannerPadding ) {
173+ Color . clear
195174
196- VStack ( spacing : 0.0 ) {
197- backgroundView ( )
175+ VStack {
176+ Spacer ( )
198177
199178 if deviceType == . iphone {
200179 scanningZoneWithInstructions
180+ }
181+ // Despite the similarities between the following views,
182+ // this is required so that `scanFrame` gets correctly updated
183+ else if mainProxy. size. width < mainProxy. size. height {
184+ VStack ( spacing: scannerPadding) {
185+ scanningZoneWithInstructions
186+ }
187+ . frame ( height: mainProxy. size. width * 0.5 )
201188 } else {
202- VStack ( spacing: 0.0 ) {
189+ VStack ( spacing: scannerPadding ) {
203190 scanningZoneWithInstructions
204191 }
205- . frame ( height: min ( mainProxy. size. width , mainProxy . size . height) * 0.5 )
192+ . frame ( height: mainProxy. size. height * 0.5 )
206193 }
207194
208- backgroundView ( )
195+ Spacer ( )
209196 }
210197 . frame ( width: mainProxy. size. width * 0.5 - scannerPadding * 2.0 )
211198
212- backgroundView ( width: screenPadding)
213-
214199 // Buttons View
215- ZStack ( alignment: . trailing) {
216- backgroundView ( )
200+ VStack ( alignment: . trailing, spacing: buttonSpacing) {
201+ // Cancel Button
202+ cancelButton
217203
218- VStack ( alignment: . trailing, spacing: buttonSpacing) {
219- // Cancel Button
220- cancelButton
221-
222- Spacer ( )
223-
224- if cameraHasTorch {
225- // Torch Button
226- torchButton
227- }
228-
229- if shouldShowButton {
230- // Scan Button
231- scanButton
232- }
233-
234- Spacer ( )
204+ Spacer ( )
205+
206+ if cameraHasTorch {
207+ // Torch Button
208+ torchButton
235209 }
210+
211+ if shouldShowButton {
212+ // Scan Button
213+ scanButton
214+ }
215+
216+ Spacer ( )
236217 }
237- . frame ( maxWidth: . infinity)
218+ . frame ( maxWidth: . infinity, alignment : . trailing )
238219 }
239220 } . padding ( screenPadding)
240221 }
0 commit comments