From 855b90b5fe1eb2dae7280930826e610e5e3cfb14 Mon Sep 17 00:00:00 2001 From: phlpsong Date: Mon, 24 Feb 2025 22:08:16 +0800 Subject: [PATCH] feat: add barcodeFrameSize prop --- .../src/main/java/com/rncamerakit/CKCamera.kt | 10 +++++++++ .../java/com/rncamerakit/CKCameraManager.kt | 12 +++++++++++ .../com/rncamerakit/barcode/BarcodeFrame.kt | 21 +++++++++++++++---- .../viewmanagers/CKCameraManagerDelegate.java | 4 ++++ .../CKCameraManagerInterface.java | 2 ++ example/src/BarcodeScreenExample.tsx | 1 + ios/ReactNativeCameraKit/CKCameraManager.m | 1 + ios/ReactNativeCameraKit/CameraProtocol.swift | 1 + ios/ReactNativeCameraKit/CameraView.swift | 10 +++++++-- ios/ReactNativeCameraKit/RealCamera.swift | 5 +++++ .../ScannerInterfaceView.swift | 21 +++++++++++++------ .../SimulatorCamera.swift | 5 +++++ src/CameraProps.ts | 1 + 13 files changed, 82 insertions(+), 12 deletions(-) diff --git a/android/src/main/java/com/rncamerakit/CKCamera.kt b/android/src/main/java/com/rncamerakit/CKCamera.kt index 5e447ecea..980cf0065 100644 --- a/android/src/main/java/com/rncamerakit/CKCamera.kt +++ b/android/src/main/java/com/rncamerakit/CKCamera.kt @@ -42,6 +42,7 @@ import android.graphics.Canvas import android.graphics.Paint import android.graphics.Rect import android.graphics.RectF +import android.util.Size import com.facebook.react.uimanager.UIManagerHelper import com.google.mlkit.vision.barcode.common.Barcode import com.rncamerakit.events.* @@ -106,6 +107,7 @@ class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObs private var scanBarcode: Boolean = false private var frameColor = Color.GREEN private var laserColor = Color.RED + private var barcodeFrameSize: Size? = null private fun getActivity() : Activity { return currentContext.currentActivity!! @@ -653,6 +655,7 @@ class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObs fun setShowFrame(enabled: Boolean) { if (enabled) { barcodeFrame = BarcodeFrame(context) + barcodeFrame!!.setFrameSize(barcodeFrameSize) val actualPreviewWidth = resources.displayMetrics.widthPixels val actualPreviewHeight = resources.displayMetrics.heightPixels val height: Int = convertDeviceHeightToSupportedAspectRatio(actualPreviewWidth, actualPreviewHeight) @@ -680,6 +683,13 @@ class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObs } } + fun setBarcodeFrameSize(size: Size) { + barcodeFrameSize = size + if (barcodeFrame != null) { + barcodeFrame!!.setFrameSize(size) + } + } + private fun convertDeviceHeightToSupportedAspectRatio(actualWidth: Int, actualHeight: Int): Int { val maxScreenRatio = 16 / 9f return (if (actualHeight / actualWidth > maxScreenRatio) actualWidth * maxScreenRatio else actualHeight).toInt() diff --git a/android/src/main/java/com/rncamerakit/CKCameraManager.kt b/android/src/main/java/com/rncamerakit/CKCameraManager.kt index 359ebaf74..85e0d9c6c 100644 --- a/android/src/main/java/com/rncamerakit/CKCameraManager.kt +++ b/android/src/main/java/com/rncamerakit/CKCameraManager.kt @@ -2,8 +2,10 @@ package com.rncamerakit import android.graphics.Color import android.util.Log +import android.util.Size import androidx.annotation.ColorInt import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.ReadableType import com.facebook.react.common.MapBuilder import com.facebook.react.common.ReactConstants.TAG @@ -116,6 +118,16 @@ class CKCameraManager : SimpleViewManager(), CKCameraManagerInterface< view.setFrameColor(color ?: Color.GREEN) } + @ReactProp(name = "barcodeFrameSize") + override fun setBarcodeFrameSize(view: CKCamera, frameSize: ReadableMap?) { + if (frameSize == null || !frameSize.hasKey("width") || !frameSize.hasKey("height")) { + return + } + val width = frameSize.getInt("width") + val height = frameSize.getInt("height") + view.setBarcodeFrameSize(Size(width, height)) + } + @ReactProp(name = "outputPath") override fun setOutputPath(view: CKCamera, path: String?) { view.setOutputPath(path ?: "") diff --git a/android/src/main/java/com/rncamerakit/barcode/BarcodeFrame.kt b/android/src/main/java/com/rncamerakit/barcode/BarcodeFrame.kt index ae694a839..d80d7afb3 100644 --- a/android/src/main/java/com/rncamerakit/barcode/BarcodeFrame.kt +++ b/android/src/main/java/com/rncamerakit/barcode/BarcodeFrame.kt @@ -2,6 +2,8 @@ package com.rncamerakit.barcode import android.content.Context import android.graphics.* +import android.util.Log +import android.util.Size import android.view.View import androidx.annotation.ColorInt @@ -14,6 +16,7 @@ class BarcodeFrame(context: Context) : View(context) { private var laserPaint: Paint = Paint() var frameRect: Rect = Rect() + private var barcodeFrameSize = DEFAULT_SIZE private var frameWidth = 0 private var frameHeight = 0 private var borderMargin = 0 @@ -31,14 +34,18 @@ class BarcodeFrame(context: Context) : View(context) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) + calculateFrameRect() + } + + private fun calculateFrameRect() { val marginHeight = 40 val marginWidth = 40 - val frameMaxWidth = 1200 - val frameMaxHeight = 600 + val frameMaxWidth = barcodeFrameSize.width * context.resources.displayMetrics.density + val frameMaxHeight = barcodeFrameSize.height * context.resources.displayMetrics.density val frameMinWidth = 100 val frameMinHeight = 100 - frameWidth = max(frameMinWidth, min(frameMaxWidth, measuredWidth - (marginWidth * 2))) - frameHeight = max(frameMinHeight, min(frameMaxHeight, measuredHeight - (marginHeight * 2))) + frameWidth = max(frameMinWidth, min(frameMaxWidth.toInt(), measuredWidth - (marginWidth * 2))) + frameHeight = max(frameMinHeight, min(frameMaxHeight.toInt(), measuredHeight - (marginHeight * 2))) frameRect.left = (measuredWidth / 2) - (frameWidth / 2) frameRect.right = (measuredWidth / 2) + (frameWidth / 2) frameRect.top = (measuredHeight / 2) - (frameHeight / 2) @@ -79,9 +86,15 @@ class BarcodeFrame(context: Context) : View(context) { laserPaint.color = laserColor } + fun setFrameSize(size: Size?) { + barcodeFrameSize = size ?: DEFAULT_SIZE + calculateFrameRect() + } + companion object { private const val STROKE_WIDTH = 5 private const val ANIMATION_SPEED = 4 + private val DEFAULT_SIZE = Size(300, 150) } init { diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerDelegate.java b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerDelegate.java index e236b839d..5ff2d5b7b 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerDelegate.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerDelegate.java @@ -12,6 +12,7 @@ import android.view.View; import androidx.annotation.Nullable; import com.facebook.react.bridge.ColorPropConverter; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.BaseViewManager; import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; @@ -56,6 +57,9 @@ public void setProperty(T view, String propName, @Nullable Object value) { case "frameColor": mViewManager.setFrameColor(view, ColorPropConverter.getColor(value, view.getContext())); break; + case "barcodeFrameSize": + mViewManager.setBarcodeFrameSize(view, value == null ? null : (ReadableMap) value); + break; case "ratioOverlay": mViewManager.setRatioOverlay(view, value == null ? null : (String) value); break; diff --git a/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerInterface.java b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerInterface.java index 25cd980c3..631ff757d 100644 --- a/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerInterface.java +++ b/android/src/paper/java/com/facebook/react/viewmanagers/CKCameraManagerInterface.java @@ -11,6 +11,7 @@ import android.view.View; import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableMap; public interface CKCameraManagerInterface { void setFlashMode(T view, @Nullable String value); @@ -24,6 +25,7 @@ public interface CKCameraManagerInterface { void setShowFrame(T view, boolean value); void setLaserColor(T view, @Nullable Integer value); void setFrameColor(T view, @Nullable Integer value); + void setBarcodeFrameSize(T view, @Nullable ReadableMap value); void setRatioOverlay(T view, @Nullable String value); void setRatioOverlayColor(T view, @Nullable Integer value); void setResetFocusTimeout(T view, int value); diff --git a/example/src/BarcodeScreenExample.tsx b/example/src/BarcodeScreenExample.tsx index 71654a794..68a11b796 100644 --- a/example/src/BarcodeScreenExample.tsx +++ b/example/src/BarcodeScreenExample.tsx @@ -147,6 +147,7 @@ const BarcodeExample = ({ onBack }: { onBack: () => void }) => { frameColor="white" scanBarcode showFrame + barcodeFrameSize={{ width: 300, height: 150 }} onReadCode={(event) => { Vibration.vibrate(100); setBarcode(event.nativeEvent.codeStringValue); diff --git a/ios/ReactNativeCameraKit/CKCameraManager.m b/ios/ReactNativeCameraKit/CKCameraManager.m index 72ac82f3e..57503ba39 100644 --- a/ios/ReactNativeCameraKit/CKCameraManager.m +++ b/ios/ReactNativeCameraKit/CKCameraManager.m @@ -29,6 +29,7 @@ @interface RCT_EXTERN_MODULE(CKCameraManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(scanThrottleDelay, NSInteger) RCT_EXPORT_VIEW_PROPERTY(laserColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(frameColor, UIColor) +RCT_EXPORT_VIEW_PROPERTY(barcodeFrameSize, NSDictionary) RCT_EXPORT_VIEW_PROPERTY(onOrientationChange, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onCaptureButtonPressIn, RCTDirectEventBlock) diff --git a/ios/ReactNativeCameraKit/CameraProtocol.swift b/ios/ReactNativeCameraKit/CameraProtocol.swift index 2fa7ece18..35bcbec50 100644 --- a/ios/ReactNativeCameraKit/CameraProtocol.swift +++ b/ios/ReactNativeCameraKit/CameraProtocol.swift @@ -20,6 +20,7 @@ protocol CameraProtocol: AnyObject, FocusInterfaceViewDelegate { func update(maxZoom: Double?) func update(resizeMode: ResizeMode) func update(maxPhotoQualityPrioritization: MaxPhotoQualityPrioritization?) + func update(barcodeFrameSize: CGSize?) func zoomPinchStart() func zoomPinchChange(pinchScale: CGFloat) diff --git a/ios/ReactNativeCameraKit/CameraView.swift b/ios/ReactNativeCameraKit/CameraView.swift index cb3a6f859..54324a653 100644 --- a/ios/ReactNativeCameraKit/CameraView.swift +++ b/ios/ReactNativeCameraKit/CameraView.swift @@ -48,6 +48,8 @@ public class CameraView: UIView { @objc public var scanThrottleDelay = 2000 @objc public var frameColor: UIColor? @objc public var laserColor: UIColor? + @objc public var barcodeFrameSize: NSDictionary? + // other @objc public var onOrientationChange: RCTDirectEventBlock? @objc public var onZoom: RCTDirectEventBlock? @@ -229,8 +231,6 @@ public class CameraView: UIView { }) } - - if changedProps.contains("showFrame") || changedProps.contains("scanBarcode") { DispatchQueue.main.async { self.scannerInterfaceView.isHidden = !self.showFrame @@ -238,6 +238,12 @@ public class CameraView: UIView { self.camera.update(scannerFrameSize: self.showFrame ? self.scannerInterfaceView.frameSize : nil) } } + + if changedProps.contains("barcodeFrameSize"), let barcodeFrameSize, showFrame, scanBarcode { + if let width = barcodeFrameSize["width"] as? CGFloat, let height = barcodeFrameSize["height"] as? CGFloat { + self.scannerInterfaceView.update(frameSize: CGSize(width: width, height: height)) + } + } if changedProps.contains("laserColor"), let laserColor { scannerInterfaceView.update(laserColor: laserColor) diff --git a/ios/ReactNativeCameraKit/RealCamera.swift b/ios/ReactNativeCameraKit/RealCamera.swift index db32602a4..65248c786 100644 --- a/ios/ReactNativeCameraKit/RealCamera.swift +++ b/ios/ReactNativeCameraKit/RealCamera.swift @@ -38,6 +38,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega private var focusFinished: (() -> Void)? private var onBarcodeRead: ((_ barcode: String,_ codeFormat : CodeFormat) -> Void)? private var scannerFrameSize: CGRect? = nil + private var barcodeFrameSize: CGSize? = nil private var onOrientationChange: RCTDirectEventBlock? private var onZoomCallback: RCTDirectEventBlock? private var lastOnZoom: Double? @@ -387,6 +388,10 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega } } + func update(barcodeFrameSize: CGSize?) { + self.barcodeFrameSize = barcodeFrameSize + } + func update(scannerFrameSize: CGRect?) { guard self.scannerFrameSize != scannerFrameSize else { return } self.sessionQueue.async { diff --git a/ios/ReactNativeCameraKit/ScannerInterfaceView.swift b/ios/ReactNativeCameraKit/ScannerInterfaceView.swift index bedfea1f8..19fb46b90 100644 --- a/ios/ReactNativeCameraKit/ScannerInterfaceView.swift +++ b/ios/ReactNativeCameraKit/ScannerInterfaceView.swift @@ -15,10 +15,12 @@ class ScannerInterfaceView: UIView { private let leftOverlayView = UIView() private let rightOverlayView = UIView() + private var barcodeFrameWidth: CGFloat = 300 + private var barcodeFrameHeight: CGFloat = 150 + // MARK: - Constants private let frameOffset: CGFloat = 30 - private let frameHeight: CGFloat = 200 private let overlayColor: UIColor = .black.withAlphaComponent(0.4) // MARK: - Lifecycle @@ -46,7 +48,7 @@ class ScannerInterfaceView: UIView { override func draw(_ rect: CGRect) { super.draw(rect) - frameView.frame = CGRect(x: 0, y: 0, width: bounds.size.width - 2 * frameOffset, height: frameHeight) + frameView.frame = CGRect(x: 0, y: 0, width: barcodeFrameWidth, height: barcodeFrameHeight) frameView.center = center updateOverlaySize(frameView.frame) @@ -74,16 +76,23 @@ class ScannerInterfaceView: UIView { frameView.update(laserColor: laserColor) } + func update(frameSize: CGSize) { + barcodeFrameWidth = frameSize.width + barcodeFrameHeight = frameSize.height + frameView.setNeedsDisplay() + setNeedsDisplay() + } + // MARK: - Private private func updateOverlaySize(_ frameRect: CGRect) { topOverlayView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frameRect.origin.y) - leftOverlayView.frame = CGRect(x: 0, y: frameRect.origin.y, width: frameOffset, height: frameHeight) - rightOverlayView.frame = CGRect(x: frameRect.size.width + frameOffset, y: frameRect.origin.y, width: frameOffset, height: frameHeight) + leftOverlayView.frame = CGRect(x: 0, y: frameRect.origin.y, width: (frame.size.width - barcodeFrameWidth) / 2, height: barcodeFrameHeight) + rightOverlayView.frame = CGRect(x: (frame.size.width - barcodeFrameWidth) / 2 + barcodeFrameWidth, y: frameRect.origin.y, width: (frame.size.width - barcodeFrameWidth) / 2, height: barcodeFrameHeight) bottomOverlayView.frame = CGRect( x: 0, - y: frameRect.origin.y + frameHeight, + y: frameRect.origin.y + barcodeFrameHeight, width: frame.size.width, - height: frame.size.height - frameRect.origin.y - frameHeight) + height: frame.size.height - frameRect.origin.y - barcodeFrameHeight) } } diff --git a/ios/ReactNativeCameraKit/SimulatorCamera.swift b/ios/ReactNativeCameraKit/SimulatorCamera.swift index b2986ce3f..854311553 100644 --- a/ios/ReactNativeCameraKit/SimulatorCamera.swift +++ b/ios/ReactNativeCameraKit/SimulatorCamera.swift @@ -18,6 +18,7 @@ class SimulatorCamera: CameraProtocol { private var zoom: Double? private var maxZoom: Double? private var resizeMode: ResizeMode = .contain + private var barcodeFrameSize: CGSize? var previewView: UIView { mockPreview } @@ -196,4 +197,8 @@ class SimulatorCamera: CameraProtocol { } } } + + func update(barcodeFrameSize: CGSize?) { + self.barcodeFrameSize = barcodeFrameSize + } } diff --git a/src/CameraProps.ts b/src/CameraProps.ts index 7138ac8be..cb63710dc 100644 --- a/src/CameraProps.ts +++ b/src/CameraProps.ts @@ -97,6 +97,7 @@ export interface CameraProps extends ViewProps { showFrame?: boolean; laserColor?: number | string; frameColor?: number | string; + barcodeFrameSize?: { width: number; height: number }; onReadCode?: (event: OnReadCodeData) => void; // Specific to iOS ratioOverlay?: string;