diff --git a/README.md b/README.md index 6163c15..2ece72d 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ You can provide a variety of extra customization options to `CodeScannerView` in - `scanMode` can be `.once` to scan a single code, `.oncePerCode` to scan many codes but only trigger finding each unique code once, and `.continuous` will keep finding codes until you dismiss the scanner. Default: `.once`. - `scanInterval` controls how fast individual codes should be scanned (in seconds) when running in `.continuous` scan mode. +- `zoomFactor` controls zoom of used capture device. By default it is nil to not interfere with videoCaptureDevice. - `showViewfinder` determines whether to show a box-like viewfinder over the UI. Default: false. - `simulatedData` allows you to provide some test data to use in Simulator, when real scanning isn’t available. Default: an empty string. - `shouldVibrateOnSuccess` allows you to determine whether device should vibrate when a code is found. Default: true. diff --git a/Sources/CodeScanner/CodeScanner.swift b/Sources/CodeScanner/CodeScanner.swift index 85b7994..57eba69 100644 --- a/Sources/CodeScanner/CodeScanner.swift +++ b/Sources/CodeScanner/CodeScanner.swift @@ -81,6 +81,7 @@ public struct CodeScannerView: UIViewControllerRepresentable { public let scanMode: ScanMode public let manualSelect: Bool public let scanInterval: Double + public let zoomFactor: CGFloat? public let showViewfinder: Bool public let requiresPhotoOutput: Bool public var simulatedData = "" @@ -96,6 +97,7 @@ public struct CodeScannerView: UIViewControllerRepresentable { scanMode: ScanMode = .once, manualSelect: Bool = false, scanInterval: Double = 2.0, + zoomFactor: CGFloat? = nil, showViewfinder: Bool = false, requiresPhotoOutput: Bool = true, simulatedData: String = "", @@ -112,6 +114,7 @@ public struct CodeScannerView: UIViewControllerRepresentable { self.showViewfinder = showViewfinder self.requiresPhotoOutput = requiresPhotoOutput self.scanInterval = scanInterval + self.zoomFactor = zoomFactor self.simulatedData = simulatedData self.shouldVibrateOnSuccess = shouldVibrateOnSuccess self.isTorchOn = isTorchOn @@ -129,6 +132,7 @@ public struct CodeScannerView: UIViewControllerRepresentable { uiViewController.parentView = self uiViewController.updateViewController( isTorchOn: isTorchOn, + zoomFactor: zoomFactor, isGalleryPresented: isGalleryPresented.wrappedValue, isManualCapture: scanMode.isManual, isManualSelect: manualSelect diff --git a/Sources/CodeScanner/ScannerViewController.swift b/Sources/CodeScanner/ScannerViewController.swift index 292194a..99c62ed 100644 --- a/Sources/CodeScanner/ScannerViewController.swift +++ b/Sources/CodeScanner/ScannerViewController.swift @@ -373,17 +373,11 @@ extension CodeScannerView { } #endif - func updateViewController(isTorchOn: Bool, isGalleryPresented: Bool, isManualCapture: Bool, isManualSelect: Bool) { + func updateViewController(isTorchOn: Bool, zoomFactor: CGFloat?, isGalleryPresented: Bool, isManualCapture: Bool, isManualSelect: Bool) { guard let videoCaptureDevice = parentView.videoCaptureDevice ?? fallbackVideoCaptureDevice else { return } - if videoCaptureDevice.hasTorch { - try? videoCaptureDevice.lockForConfiguration() - videoCaptureDevice.torchMode = isTorchOn ? .on : .off - videoCaptureDevice.unlockForConfiguration() - } - if isGalleryPresented, !isGalleryShowing { openGallery() } @@ -392,6 +386,26 @@ extension CodeScannerView { showManualCaptureButton(isManualCapture) showManualSelectButton(isManualSelect) #endif + + let needsZoomUpdate = zoomFactor != nil && videoCaptureDevice.videoZoomFactor != zoomFactor + + guard videoCaptureDevice.hasTorch || needsZoomUpdate else { return } + + try? videoCaptureDevice.lockForConfiguration() + + if videoCaptureDevice.hasTorch { + videoCaptureDevice.torchMode = isTorchOn ? .on : .off + } + + if needsZoomUpdate, let zoomFactor { + let newFactor = max( + videoCaptureDevice.minAvailableVideoZoomFactor, + min(videoCaptureDevice.maxAvailableVideoZoomFactor, zoomFactor) + ) + videoCaptureDevice.videoZoomFactor = newFactor + } + + videoCaptureDevice.unlockForConfiguration() } public func reset() {