iOS-swfit-原生二维码扫描

2018-08-16  本文已影响0人  Cary9396

前段时间项目有个二维码扫描的需求,于是就研究了一下。发现了挺多第三方,例如ZBar,ZXing。第三方的确功能强大,但并不一定是最好选择。 如果你的项目只是需要简单的扫描功能。并不需要它特别强大的话,完全可以抛弃第三方,自己写原生代码。实现起来非常简单。今天我们来说一个swfit版本的原生二维码。

废话不多说,上代码:

override func viewDidLoad() {
        super.viewDidLoad()
        judgeCameraPermission()
        setupView()
    }

首先我们需要判读一下相机设备是否可用,记得在plist文件添加相机权限,这个不多说了。

 func judgeCameraPermission() {
        //拒绝,受限制
        let status = AVCaptureDevice.authorizationStatus(for: .video)
        if status == .restricted || status == .denied {
            print("没有权限使用!")
        }
        else if status == .notDetermined {
         
            AVCaptureDevice.requestAccess(for: .video) { (allow) in
                if allow {
                    print("同意了")
                    self.initSession()
                    self.initScanView()
                    self.session?.startRunning()
                }
                else {
                    print("拒绝了")
                }
            }
            
            
        }
        else {
           initSession()
        }
    }

用session生成一个AVCaptureVideoPreviewLayer添加到view的layer上,实时显示摄像头捕捉的内容:

  func initScanView() {
    
        let layer = AVCaptureVideoPreviewLayer(session: session!)
        layer.videoGravity = .resizeAspectFill
        layer.frame = UIScreen.main.bounds
        view.layer.insertSublayer(layer, at: 0)

    }

创建session 设置采集时的参数:

func initSession() {
        
        let device = AVCaptureDevice.default(for: .video)
        do {
            let input = try AVCaptureDeviceInput(device: device!) //创建摄像头输入流
            let output = AVCaptureMetadataOutput() //创建输出流
            output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            //设置扫描区域
            let widthS = 300 / xScreenHeight
            let heightS = 300 / xScreenWidth
             output.rectOfInterest = CGRect(x: (1-widthS)/2, y: (1-heightS)/2, width: widthS, height: heightS)
            session = AVCaptureSession()
            //采集率质量
            session?.sessionPreset = .high
            session?.addInput(input)
            session?.addOutput(output)
            output.metadataObjectTypes = [.qr,.ean13,.ean8,.code128]
            
        } catch let err as NSError {
            
            print("发生错误:\(String(describing: err.localizedFailureReason))")
        } 
    }

设置扫描时候的UI界面:

 func setupView() {
        
        title = "扫描二维码"
        view.backgroundColor = UIColor.white
        view.addSubview(MaskView(frame: UIScreen.main.bounds))
        if session != nil {
            
            initScanView()
        }
        
    }
class MaskView: UIView {
    var lineLayer:CALayer!
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.black.withAlphaComponent(0.1)
        
        lineLayer = CALayer()
        lineLayer.frame = CGRect(x: (frame.width-300)/2, y: (frame.height-300)/2, width: 300, height: 2)
        lineLayer.contents = UIImage(named: "line")?.cgImage
        layer.addSublayer(lineLayer)
        resumeAnimation()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect:CGRect){
    
        let width:CGFloat = rect.size.width
        let height:CGFloat = rect.size.height
        let pickingWidth:CGFloat = 300
        let pickingHeight:CGFloat = 300
        
        let context = UIGraphicsGetCurrentContext()
        context?.saveGState()
        context?.setFillColor(red:0.1,green:0.1,blue:0.1,alpha:0.35)
        let pickingRect = CGRect(x: (width-pickingWidth)/2, y: (height-pickingHeight)/2, width: pickingWidth, height: pickingHeight)
        
        let pickingPath = UIBezierPath(rect: pickingRect)
        let bezierRect = UIBezierPath(rect: rect)
        bezierRect.append(pickingPath)
        bezierRect.usesEvenOddFillRule = true
        bezierRect.fill()
        context?.setLineWidth(2)
        context?.setStrokeColor(UIColor.orange.cgColor)
        pickingPath.stroke()
        layer.contentsGravity = kCAGravityCenter

    }
    
    func stopAnimation() {
       
        lineLayer.removeAnimation(forKey: "translationY")
    }
    
    func resumeAnimation() {
       
        let basic = CABasicAnimation(keyPath: "transform.translation.y")
        basic.fromValue = 0
        basic.toValue = 300
        basic.duration = 2
        basic.repeatCount = Float(NSIntegerMax)
        lineLayer.add(basic, forKey: "translationY")
        
    }
}

扫描后执行的delegate方法:

 func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        
        if metadataObjects.count > 0 {
    
            let metadata = metadataObjects.first  as! AVMetadataMachineReadableCodeObject
            let alert = UIAlertController(title: "扫描结果", message:metadata.stringValue, preferredStyle:.alert)
            let action = UIAlertAction(title: "确定", style: .default, handler: nil)
            alert.addAction(action)
            present(alert, animated: true, completion: nil)
        }
    }

页面进来的时候记得开启session,离开时记得关闭session:

 override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        session?.startRunning()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        session?.stopRunning()
    }

此时便已大功告成,已经实现了一个简单的二维码识别的功能。识别相册图片二维码的功能后期再加上。
具体可查看Demo:
https://github.com/WisdomWang/CAQRCode

如果你需要oc版本的 给你推荐一个 这个作者写的功能也很全面。你可以参考写自己想要的二维码功能。链接:
https://github.com/kingsic/SGQRCode

识别相册二维码图片功能已加,请查看上方Demo。

上一篇下一篇

猜你喜欢

热点阅读