如何在按钮按下时扫描二维码?

Posted

技术标签:

【中文标题】如何在按钮按下时扫描二维码?【英文标题】:How to scan for QR codes on button press? 【发布时间】:2016-03-21 08:22:39 【问题描述】:

我正在使用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
        
         

【问题讨论】:

【参考方案1】:

该教程的作者在这里。我的方法是使用专用的扫描视图控制器,但我猜你想将它与现有的视图控制器统一起来——这很好。两种方法都有效。

如果您想一直显示相机界面(即使不主动识别 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 以节省不必要的方法调用。

【讨论】:

tx 为您的教程。我将检查是否可以将您的代码建议(使用 foundcode 函数)用于我的“混乱”设置。我用一些似乎可以完成工作的代码编辑/更新了我的原始问题。顺便说一句:我注意到 metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode] 向数组添加类型似乎不起作用,只有第一个 ObjectType 似乎可以识别输入。就我而言,我有要扫描的二维码和条形码。【参考方案2】:

感谢@alex 提出这个问题。我还使用了twostraws创建的优秀类(非常有用的Paul,非常感谢),并且还需要仅通过按钮操作来实现扫码阅读。我的解决方案如下:

我将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)

【讨论】:

以上是关于如何在按钮按下时扫描二维码?的主要内容,如果未能解决你的问题,请参考以下文章

怎么实现扫描二维码跳转到指定页面

.net 手机扫描二维码功能

微信扫描二维码无效是怎么回事?

如何实现微信扫描二维码直接在手机浏览器打开网页

iOS系统原生二维码条形码扫描

如何使用Android相机扫描二维码