Quantcast
Channel: Recent Questions - Stack Overflow
Viewing all articles
Browse latest Browse all 16030

CameraView not displaying when used with a sheet view in SwiftUI

$
0
0

I would like to have a camera view show up in sheet view to be able to scan barcodes.For some reason, the camera layer created doesn't want to appear in the sheet view, even though the green dot appears on the iPhone, or the logs say that everything is fine.

// MainView.swift@State private var showScanSheet = falsevar body: some View {  NavigationStack {    VStack {      ...    }.sheet(isPresented: $showScanSheet) {      ScannerView()    }  }}
// ScannerView.swiftimport SwiftUIimport AVKitstruct ScannerView: View {    @State private var isScanning: Bool = false    @State private var session: AVCaptureSession = .init()    @State private var cameraPermission: Permission = .idle    @State private var barcodeOutput: AVCaptureMetadataOutput = .init()    @State private var errorMessage: String = ""    @State private var showError: Bool = false    @Environment(\.openURL) private var openURL    @StateObject private var barcodeDelegate = BarcodeScannerDelegate()    var body: some View {        GeometryReader {            let size = $0.size            ZStack {                CameraView(frameSize: CGSize(width: size.width, height: 200), session: $session).scaleEffect(0.97)                RoundedRectangle(cornerRadius: 10, style: .circular)                    .trim(from: 0.55, to: 0.60)                    .stroke(Color.red, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))                    .padding()                RoundedRectangle(cornerRadius: 10, style: .circular)                    .trim(from: 0.55, to: 0.60)                    .stroke(Color.red, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))                    .rotationEffect(.init(degrees: 180))                    .padding()                RoundedRectangle(cornerRadius: 10, style: .circular)                    .trim(from: 0.40, to: 0.45)                    .stroke(Color.red, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))                    .padding()                RoundedRectangle(cornerRadius: 10, style: .circular)                    .trim(from: 0.40, to: 0.45)                    .stroke(Color.red, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))                    .rotationEffect(.init(degrees: 180))                    .padding()            }            .frame(width: size.width, height: 200)            .frame(maxWidth: .infinity, maxHeight: .infinity)        }        .onAppear(perform: checkCameraPermission)        .alert(errorMessage, isPresented: $showError) {            if cameraPermission == .denied {                Button("Settings") {                    let settingsString = UIApplication.openSettingsURLString                    if let settingsURL = URL(string: settingsString) {                        openURL(settingsURL)                    }                }                Button("Cancel", role: .cancel) {}            }        }    }    func checkCameraPermission() {        print("Checking camera permission")        Task {            switch AVCaptureDevice.authorizationStatus(for: .video) {            case .authorized:                cameraPermission = .approved                setupCamera()            case .notDetermined, .denied, .restricted:                if await AVCaptureDevice.requestAccess(for: .video) {                    cameraPermission = .approved                    setupCamera()                } else {                    cameraPermission = .denied                    presentError("Please provide access to the camera for scanning barcodes.")                }            default: break            }            print(cameraPermission)        }    }    func setupCamera() {        do {            guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInUltraWideCamera], mediaType: .video, position: .back).devices.first else {                presentError("Unknown error.")                return            }            let input = try AVCaptureDeviceInput(device: device)            guard session.canAddInput(input),  session.canAddOutput(barcodeOutput) else {                presentError("Unknown error.")                return            }            session.beginConfiguration()            session.addInput(input)            session.addOutput(barcodeOutput)            barcodeOutput.metadataObjectTypes = [.upce, .ean8, .ean13]            barcodeOutput.setMetadataObjectsDelegate(barcodeDelegate, queue: .main)            session.commitConfiguration()            DispatchQueue.global(qos: .background).async {                session.startRunning()            }        } catch {            presentError(error.localizedDescription)        }    }    func presentError(_ message: String) {        errorMessage = message        showError.toggle()    }}
// BarcodeScannerDelegate.swiftimport Foundationimport AVKitclass BarcodeScannerDelegate: NSObject, ObservableObject, AVCaptureMetadataOutputObjectsDelegate {    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {        if let metadataObject = metadataObjects.first {            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }            guard let scannedCode = readableObject.stringValue else { return }            print(scannedCode)        }    }}
// CameraView.swiftimport SwiftUIimport AVKitstruct CameraView: UIViewRepresentable {    var frameSize: CGSize    @Binding var session: AVCaptureSession    func makeUIView(context: Context) -> UIView {        let view = UIViewType(frame: CGRect(origin: .zero, size: frameSize))        view.backgroundColor = .clear        let cameraLayer = AVCaptureVideoPreviewLayer(session: session)        cameraLayer.frame = .init(origin: .zero, size: frameSize)        cameraLayer.videoGravity = .resizeAspectFill        cameraLayer.masksToBounds = true        view.layer.addSublayer(cameraLayer)        return view    }    func updateUIView(_ uiView: UIViewType, context: Context) {    }}

When using with .sheet

However, the app works completely as expected when instead of using a sheet, I use a fullScreenCover or a navigationDestination in MainView.swift.

when using with fullScreenCover

Thank you for your help.


Viewing all articles
Browse latest Browse all 16030

Latest Images

Trending Articles



Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>