Как сканировать QR-коды при нажатии кнопки?

Я использую код, предоставленный https://www.hackingwithswift.com/example-code/media/how-to-scan-a-qr-code чтобы создать собственное приложение для сканирования. Но мне нравится, что мое сканирование происходит при нажатии кнопки. Теперь для этого я поставил viewDidLoad() часть из учебника в его собственную функцию:

func cameraScanningLayer(){
    view.backgroundColor = UIColor.blackColor()
    captureSession = AVCaptureSession()

    let videoCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    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: dispatch_get_main_queue())
        // need to scan barcode + QRcode
        metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code,AVMetadataObjectTypeCode128Code,AVMetadataObjectTypeCode39Code]
    } else {
        failed()
        return
    }

    // Previewlayer with camera
    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession);
    previewLayer.frame = viewForLayer.bounds;
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    viewForLayer.layer.addSublayer(previewLayer);

    captureSession.startRunning();
}

И действие кнопки вызывает функцию:

func buttonScanAction() {
    print("Scan")
    scanEnabled = true // like to use some kind of bool/switch
    self.cameraScanningLayer()
}

У меня есть следующие проблемы:

1) при загрузке камера не видна

2) После нажатия кнопки камера видна, но она всегда сканирует автоматически

Поэтому я подумал об использовании глобального:

var scanEnabled: Bool = false

Затем, когда кнопка нажата, установите для нее значение true, и сканирование будет включено.

Для справки вот эскиз:

введите описание изображения здесь

РЕДАКТИРОВАТЬ мое быстрое исправление, которое может быть неправильным способом сделать это.

Я заменил

 let metadataOutput = AVCaptureMetadataOutput() {...} else {
            failed()
            return
        }

и положить его между утверждением if

if (scanEnabled == true) {

        let metadataOutput = AVCaptureMetadataOutput()

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

            metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
            // to use them both wwe need to skip AVMetadataObjectTypeQRCode
            metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code,AVMetadataObjectTypeCode128Code,AVMetadataObjectTypeCode39Code]
            scanEnabled = false
        } else {
            failed()
            return
        }
        } 

2 ответа

Автор этого урока здесь. Мой метод состоял в том, чтобы использовать выделенный контроллер вида сканирования, но я предполагаю, что вы хотите объединить это с вашим существующим контроллером представления - и это нормально. Оба подхода работают.

Если вы хотите показывать интерфейс камеры все время (даже когда не распознаете QR-коды), тогда ваш план использовать логическое значение для отслеживания того, включено ли сканирование, является хорошим. Мой пример кода имеет foundCode() метод, который вызывается, а также вызывает dismissViewControllerAnimated() когда коды найдены.

В вашей версии нужно сделать foundCode() выполнять всю работу по остановке проверки, обработке увольнения и т. д. Затем вы можете добавить чек для вашего scanEnabled логическое в одном месте.

Нечто подобное должно сделать это:

func foundCode(code: String) {
    if scanCode == true {
        print(code)

        captureSession.stopRunning()
        AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
        dismissViewControllerAnimated(true, completion: nil)
    }
}

Если бы вы хотели, вы могли бы переместить scanCode == true проверить до didOutputMetadataObjects сохранить ненужный вызов метода.

Спасибо @alex за этот вопрос. Я также использую отличный класс, созданный twostraws (очень полезный, Пол, большое спасибо), а также мне нужно реализовать чтение сканирования кода с помощью только действия кнопки. Мое решение было следующим:

Я определяю metadataOutput как глобальная переменная и только в действие кнопки я интегрирую их как делегат:

      var metadataOutput: AVCaptureMetadataOutput!

В viewDidLoad метод:

      metadataOutput = AVCaptureMetadataOutput()

if (captureSession.canAddOutput(metadataOutput)) {
    captureSession.addOutput(metadataOutput)
    // Was removed this line: metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
    metadataOutput.metadataObjectTypes = [.qr]
} else {
    failed()
    return
}

func buttonScanAction() {
    print("Scan")
    metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
}

Когда я меняю свое мнение, я останавливаю камеру и удаляю делегата следующим образом:

      override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if (captureSession?.isRunning == true) {
        captureSession.stopRunning()
    }
    metadataOutput.setMetadataObjectsDelegate(nil, queue: DispatchQueue.main)
}
Другие вопросы по тегам