美文网首页
iOS-swfit-原生二维码扫描

iOS-swfit-原生二维码扫描

作者: Cary9396 | 来源:发表于2018-08-16 11:01 被阅读0次

    前段时间项目有个二维码扫描的需求,于是就研究了一下。发现了挺多第三方,例如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。

    相关文章

      网友评论

          本文标题:iOS-swfit-原生二维码扫描

          本文链接:https://www.haomeiwen.com/subject/ydenbftx.html