【问题标题】:iOS Swift Barcode ReadingiOS Swift 条码读取
【发布时间】:2015-07-01 20:11:08
【问题描述】:

我的应用程序中有条码扫描功能。检测到条形码后,我停止捕获会话以允许处理条形码。但是,在处理完条形码后,我希望扫描控制器保持正常状态并扫描下一个条形码。我曾假设启动捕获会话(startRunning())会这样做,但图像保持冻结状态。如何重新开始捕获会话?

【问题讨论】:

标签: ios swift barcode


【解决方案1】:

要停止会话,请使用此代码

self.session.stopRunning()

要重新开始,请使用此代码

self.session.startRunning()

这是实现条码扫描器的所有代码...

import UIKit
import AVFoundation

class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    let session         : AVCaptureSession = AVCaptureSession()
    var previewLayer    : AVCaptureVideoPreviewLayer!
    var highlightView   : UIView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Allow the view to resize freely
        self.highlightView.autoresizingMask =   
            UIViewAutoresizing.FlexibleTopMargin |
            UIViewAutoresizing.FlexibleBottomMargin |
            UIViewAutoresizing.FlexibleLeftMargin |
            UIViewAutoresizing.FlexibleRightMargin

        // Select the color you want for the completed scan reticle
        self.highlightView.layer.borderColor = UIColor.greenColor().CGColor
        self.highlightView.layer.borderWidth = 3

        // Add it to our controller's view as a subview.
        self.view.addSubview(self.highlightView)

        // For the sake of discussion this is the camera
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

        // Create a nilable NSError to hand off to the next method.
        // Make sure to use the "var" keyword and not "let"
        var error : NSError? = nil

        let input : AVCaptureDeviceInput? =
            AVCaptureDeviceInput.deviceInputWithDevice(device, error: &error) 
                as? AVCaptureDeviceInput

        // If our input is not nil then add it to the session, otherwise we're kind of done!
        if input != nil {
            session.addInput(input)
        } else {
            // This is fine for a demo, do something real with this in your app. :)
            println(error)
        }

        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        session.addOutput(output)
        output.metadataObjectTypes = output.availableMetadataObjectTypes

        previewLayer =
            AVCaptureVideoPreviewLayer.layerWithSession(session) 
                as! AVCaptureVideoPreviewLayer
        previewLayer.frame = self.view.bounds
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.view.layer.addSublayer(previewLayer)

        // Start the scanner. You'll have to end it yourself later.
        session.startRunning()
    }

    // This is called when we find a known barcode type with the camera.
    func captureOutput(
        captureOutput: AVCaptureOutput!, 
        didOutputMetadataObjects metadataObjects: [AnyObject]!,
        fromConnection connection: AVCaptureConnection!) {

        var highlightViewRect = CGRectZero
        var barCodeObject : AVMetadataObject!
        var detectionString : String!

        let barCodeTypes = [AVMetadataObjectTypeUPCECode,
            AVMetadataObjectTypeCode39Code,
            AVMetadataObjectTypeCode39Mod43Code,
            AVMetadataObjectTypeEAN13Code,
            AVMetadataObjectTypeEAN8Code,
            AVMetadataObjectTypeCode93Code,
            AVMetadataObjectTypeCode128Code,
            AVMetadataObjectTypePDF417Code,
            AVMetadataObjectTypeQRCode,
            AVMetadataObjectTypeAztecCode]

        // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan.
        for metadata in metadataObjects {

            for barcodeType in barCodeTypes {

                if metadata.type == barcodeType {
                    barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject)
                    highlightViewRect = barCodeObject.bounds
                    detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
                    self.session.stopRunning()
                    self.alert(detectionString)
                    break
                }
            }
        }

        println(detectionString)
        self.highlightView.frame = highlightViewRect
        self.view.bringSubviewToFront(self.highlightView)
    }        

    func alert(Code: String){
        let actionSheet:UIAlertController = 
            UIAlertController(
                title: "Barcode", 
                message: "\(Code)", 
                preferredStyle: UIAlertControllerStyle.Alert)

        // for alert add .Alert instead of .Action Sheet
        // start copy
        let firstAlertAction:UIAlertAction = 
            UIAlertAction(
                title: "OK",
                style: UIAlertActionStyle.Default, 
                handler: { (alertAction: UIAlertAction!) in
                // action when pressed
                self.session.startRunning()      
        })

        actionSheet.addAction(firstAlertAction)
        // end copy
        self.presentViewController(actionSheet, animated: true, completion: nil)
    }  
}

【讨论】:

  • 如果可行,请不要忘记将此答案标记为正确。
  • 我在做几乎相同的事情,但我交换了两行代码。我将结果字符串发送给我的处理程序,然后停止会话。它不会重新启动。如果我在将结果发送给我的处理程序之前停止了会话,那么它就起作用了。
  • 在此处添加了 Swift 3 版本:stackoverflow.com/a/41512546/2108523
【解决方案2】:

为 swift 2.0 编辑了上述代码:

import UIKit
import AVFoundation

class BarCodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    let session         : AVCaptureSession = AVCaptureSession()
    var previewLayer    : AVCaptureVideoPreviewLayer!
    @IBOutlet weak var highlightView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Select the color you want for the completed scan reticle
        self.highlightView.layer.borderColor = UIColor.greenColor().CGColor
        self.highlightView.layer.borderWidth = 3

        // Add it to our controller's view as a subview.
        self.view.addSubview(self.highlightView)

        // For the sake of discussion this is the camera
        let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

        // Create a nilable NSError to hand off to the next method.
        // Make sure to use the "var" keyword and not "let"
        var error : NSError? = nil
        var input: AVCaptureDeviceInput = AVCaptureDeviceInput()
        do {
            input = try  AVCaptureDeviceInput(device: device) as AVCaptureDeviceInput
        } catch let myJSONError {
            print(myJSONError)
        }

        // If our input is not nil then add it to the session, otherwise we're kind of done!
        if input !=  AVCaptureDeviceInput() {
            session.addInput(input)
        }
        else {
            // This is fine for a demo, do something real with this in your app. :)
            print(error)
        }

        let output = AVCaptureMetadataOutput()
        output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
        session.addOutput(output)
        output.metadataObjectTypes = output.availableMetadataObjectTypes

        previewLayer = AVCaptureVideoPreviewLayer(session: session)
        previewLayer.frame = self.view.bounds
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.view.layer.addSublayer(previewLayer)

        // Start the scanner. You'll have to end it yourself later.
        session.startRunning()
    }

    // This is called when we find a known barcode type with the camera.
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
        var highlightViewRect = CGRectZero
        var barCodeObject : AVMetadataObject!
        var detectionString : String!
        let barCodeTypes = [AVMetadataObjectTypeUPCECode,
            AVMetadataObjectTypeCode39Code,
            AVMetadataObjectTypeCode39Mod43Code,
            AVMetadataObjectTypeEAN13Code,
            AVMetadataObjectTypeEAN8Code,
            AVMetadataObjectTypeCode93Code,
            AVMetadataObjectTypeCode128Code,
            AVMetadataObjectTypePDF417Code,
            AVMetadataObjectTypeQRCode,
            AVMetadataObjectTypeAztecCode
        ]

        // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan.
        for metadata in metadataObjects {

            for barcodeType in barCodeTypes {

                if metadata.type == barcodeType {
                    barCodeObject = self.previewLayer.transformedMetadataObjectForMetadataObject(metadata as! AVMetadataMachineReadableCodeObject)

                    highlightViewRect = barCodeObject.bounds
                    detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
                    self.session.stopRunning()
                    self.alert(detectionString)
                    break
                }
            }
        }

        print(detectionString)
        self.highlightView.frame = highlightViewRect
        self.view.bringSubviewToFront(self.highlightView)
    }

    func alert(Code: String){
        let actionSheet:UIAlertController = UIAlertController(title: "Barcode", message: "\(Code)", preferredStyle: UIAlertControllerStyle.Alert)

        // for alert add .Alert instead of .Action Sheet
        // start copy

        let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: {
                (alertAction:UIAlertAction!) in
                // action when pressed
                self.session.startRunning()  
        })

        actionSheet.addAction(firstAlertAction)

        // end copy
        self.presentViewController(actionSheet, animated: true, completion: nil)
    }
}

【讨论】:

    【解决方案3】:

    Swift 3.0 版本:

    import UIKit
    import AVFoundation
    
    class BarCodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    
        let session         : AVCaptureSession = AVCaptureSession()
        var previewLayer    : AVCaptureVideoPreviewLayer!
        @IBOutlet weak var highlightView: UIView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.highlightView.layer.borderColor = UIColor.green.cgColor
            self.highlightView.layer.borderWidth = 3
    
            // Add it to our controller's view as a subview.
            self.view.addSubview(self.highlightView)
    
            // For the sake of discussion this is the camera
            let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
    
            // Create a nilable NSError to hand off to the next method.
            // Make sure to use the "var" keyword and not "let"
            var error : NSError? = nil
            var input: AVCaptureDeviceInput = AVCaptureDeviceInput()
            do {
                input = try  AVCaptureDeviceInput(device: device) as AVCaptureDeviceInput
            } catch let myJSONError {
                print(myJSONError)
            }
    
            // If our input is not nil then add it to the session, otherwise we're kind of done!
            if input !=  AVCaptureDeviceInput() {
                session.addInput(input)
            }
            else {
                // This is fine for a demo, do something real with this in your app. :)
                print(error!)
            }
    
            let output = AVCaptureMetadataOutput()
            output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            session.addOutput(output)
            output.metadataObjectTypes = output.availableMetadataObjectTypes
    
            previewLayer = AVCaptureVideoPreviewLayer(session: session)
            previewLayer.frame = self.view.bounds
            previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            self.view.layer.addSublayer(previewLayer)
    
            // Start the scanner. You'll have to end it yourself later.
            session.startRunning()
        }
    
        // This is called when we find a known barcode type with the camera.
        @nonobjc func captureOutput(
            captureOutput: AVCaptureOutput!, 
            didOutputMetadataObjects metadataObjects: [AnyObject]!,
            fromConnection connection: AVCaptureConnection!) {
    
            var highlightViewRect = CGRect()
            var barCodeObject : AVMetadataObject!
            var detectionString : String!
            let barCodeTypes = [AVMetadataObjectTypeUPCECode,
                AVMetadataObjectTypeCode39Code,
                AVMetadataObjectTypeCode39Mod43Code,
                AVMetadataObjectTypeEAN13Code,
                AVMetadataObjectTypeEAN8Code,
                AVMetadataObjectTypeCode93Code,
                AVMetadataObjectTypeCode128Code,
                AVMetadataObjectTypePDF417Code,
                AVMetadataObjectTypeQRCode,
                AVMetadataObjectTypeAztecCode]
    
            // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan.
            for metadata in metadataObjects {
                for barcodeType in barCodeTypes {
                    if metadata.type == barcodeType {
                        barCodeObject = self.previewLayer.transformedMetadataObject(for: metadata as! AVMetadataMachineReadableCodeObject)
                        highlightViewRect = barCodeObject.bounds
                        detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
                        self.session.stopRunning()
                        self.alert(Code: detectionString)
                        break
                    } 
                }
            }
    
            print(detectionString)
            self.highlightView.frame = highlightViewRect
            self.view.bringSubview(toFront: self.highlightView)
        }
    
        func alert(Code: String){
            let actionSheet:UIAlertController = UIAlertController(title: "Barcode", message: "\(Code)", preferredStyle: UIAlertControllerStyle.alert)
            // for alert add .Alert instead of .Action Sheet
    
            // start copy
            let firstAlertAction:UIAlertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (alertAction: UIAlertAction!) in
                // action when pressed              
                self.session.startRunning()
            })
    
            actionSheet.addAction(firstAlertAction)
    
            // end copy
            self.present(actionSheet, animated: true, completion: nil)
        }
    }
    

    【讨论】:

      【解决方案4】:

      Swift 5更新

       func captureOutput(
            captureOutput: AVCaptureOutput,
            didOutputMetadataObjects metadataObjects: [AnyObject],
            fromConnection connection: AVCaptureConnection,
            barCodeType: [AVMetadataObject.ObjectType]) -> String? {
      
          var detectionString: String?
          var highlightViewRect = CGRect()
          let barCodeTypes = barCodeType
          if let metadataObject = metadataObjects.first {
                for barcodeType in barCodeTypes {
                    if metadataObject.type == barcodeType {
                      guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return String()}
                      guard let barCodeObject = self.previewLayer.transformedMetadataObject(for: readableObject) else { return String()}
                      highlightViewRect = barCodeObject.bounds
                      detectionString = readableObject.stringValue
                     
                      self.captureSession.stopRunning()
                        break
                    }
                }
            }
      
          self.qrView.frame = highlightViewRect
          self.view.bringSubviewToFront(self.qrView)
          return detectionString
        }
      

      【讨论】:

      • 投反对票,因为这只是接受答案的一部分。
      猜你喜欢
      • 1970-01-01
      • 2020-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多