簡體   English   中英

在 Xcode 11、SwiftUI 中出現 UIViewController 的問題

[英]Issues presenting UIViewController in Xcode 11, SwiftUI

我有一個 QR 碼掃描儀,它嵌入在 UIViewController 中。 我一直在查看其他帖子和博客,但它們都是單頁應用程序,在應用程序啟動時將 UIViewController 作為主要應用程序。 我只需要它在按鈕操作中打開,由於某種原因我無法正確顯示掃描儀?

這是QR掃描儀代碼:

class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    var captureSession: AVCaptureSession!
    var previewLayer: AVCaptureVideoPreviewLayer!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.black
        captureSession = AVCaptureSession()

        guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
        let videoInput: AVCaptureDeviceInput

        do {
            videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
        } catch {
            return
        }

        if (captureSession.canAddInput(videoInput)) {
            captureSession.addInput(videoInput)
        } else {
            failed()
            return
        }

        let metadataOutput = AVCaptureMetadataOutput()

        if (captureSession.canAddOutput(metadataOutput)) {
            captureSession.addOutput(metadataOutput)

            metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            metadataOutput.metadataObjectTypes = [.qr]
        } else {
            failed()
            return
        }

        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer.frame = view.layer.bounds
        previewLayer.videoGravity = .resizeAspectFill
        view.layer.addSublayer(previewLayer)

        captureSession.startRunning()
    }

    func failed() {
        let ac = UIAlertController(title: "Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.", preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "OK", style: .default))
        present(ac, animated: true)
        captureSession = nil
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        if (captureSession?.isRunning == false) {
            captureSession.startRunning()
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        if (captureSession?.isRunning == true) {
            captureSession.stopRunning()
        }
    }

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        captureSession.stopRunning()

        if let metadataObject = metadataObjects.first {
            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
            guard let stringValue = readableObject.stringValue else { return }
            AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
            found(code: stringValue)
        }

        dismiss(animated: true)
    }

    func found(code: String) {
        print(code)
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }
}

這是我的(非常簡單的)嘗試在按下按鈕時打開它:

struct ScanView: View{
    
    var body: some View{
        VStack {
            Button(action: {
                ScannerViewController()
            }) {
                Text("Scan QR Code").foregroundColor(Color.white).padding()
            }.frame(width: 150)
            .background(Color.blue)
            .cornerRadius(25)
        }
    }
}

我已經嘗試查看有關這些類型問題的其他一些 StackOverflow 帖子,但有些帖子要么使用不推薦使用的掃描二維碼的方式,要么與我面臨的問題無關。

我確信這很簡單,但我的 Swift/Xcode 專業知識主要涉及設計和樣式以及 API 調用的基本知識,但我不一定了解不同的視圖層次結構和調用方法是如何工作的。

當然,我想解決這個問題,但我也想知道問題是什么,以便下次知道。

我們不能在SwiftUI UIViewController 需要UIViewControllerRepresentable來呈現UIViewController

你可以在這里讀到它:

試試這個,它正在工作,我可以通過相機看到內容:

import SwiftUI
import UIKit
import AVFoundation

struct ScannerView: UIViewControllerRepresentable {
    typealias UIViewControllerType = ScannerViewController

    func updateUIViewController(_ uiViewController: ScannerViewController, context: Context) {
        print("update")
    }

    func makeUIViewController(context: Context) -> ScannerViewController {
        return ScannerViewController()
    }

}

在你struct ScanView 中:

struct ContentView: View {
    @State private var showingScanner = false
    var body: some View {
        VStack {
            Button(action: {
                self.showingScanner = true
            }) {
                Text("Scan QR Code").foregroundColor(Color.white).padding()
            }.frame(width: 150)
            .background(Color.blue)
            .cornerRadius(25)
        }.sheet(isPresented: $showingScanner) {
            ScannerView()
        }
    }
}

攝像頭視圖,我已經將攝像頭視圖拖到了下面,這樣您就可以在后台看到按鈕屏幕:

在此處輸入圖像描述

PS 不要忘記在info.plist中添加Privacy - Camera Usage Description

我不是 xCode 專家。 更不用說 SwiftUI 專家了。 但看起來您正試圖從 SwiftUI 視圖導航到 UIKit 視圖。 這讓我愣了一分鍾。

無論如何,您將希望將您的按鈕包裝在 NavigationView 中。 https://www.hackingwithswift.com/articles/216/complete-guide-to-navigationview-in-swiftui

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM