美文网首页
2018-07-28 swift 二维码扫描功能

2018-07-28 swift 二维码扫描功能

作者: 北你妹的风 | 来源:发表于2018-07-27 14:50 被阅读124次

可以参考,用swift实现的二维码扫描功能,包括扫码,闪光灯,颜色渐变等知识点

importAVFoundation

import UIKit

class YTScanVehicleViewController:UIViewController{

    private letscanViewSize :CGFloat= 250

    private letflashViewSize :CGFloat= 72

    private letblueColor:UIColor=UIColor(red: 45/255.0, green: 100/255.0, blue: 245/255.0, alpha: 1)

    private letgrayColor:UIColor=UIColor(red: 79/255.0, green: 85/255.0, blue: 108/255.0, alpha: 1)

    private var scanView:YTScanQRCodeView?

    private var flashView:UIView?

    private var flashFlag :Bool=false

    private let session:AVCaptureSession = AVCaptureSession()

    private var layer:AVCaptureVideoPreviewLayer?

    private lazy vargradientLayer:CAGradientLayer= {

        letcolorArray:[CGColor] = [UIColor(red: 16/255.0, green: 69/255.0, blue: 150/255.0, alpha: 1).cgColor,UIColor(red: 0/255.0, green: 29/255.0, blue: 78/255.0, alpha: 1).cgColor]

        letgradientLocations:[NSNumber] = [0.0, 1.0]

        letgradientLayer =CAGradientLayer()

        gradientLayer.colors= colorArray

        gradientLayer.locations= gradientLocations

        gradientLayer.frame=CGRect(x: 0, y: 0, width:flashViewSize, height:flashViewSize)

        gradientLayer.masksToBounds=true;

        gradientLayer.cornerRadius=flashViewSize/2

        returngradientLayer

    }()

    public   varscanResult: ((_code:Int,_result:String)->Void)?//声明扫描结果的闭包

    overridefuncviewDidLoad() {

        super.viewDidLoad()

        initNavBar()

        initView()

        initScanView()

        initCaptureSession()

    }

    //MARK:  view 生命周期

    override func viewWillAppear(_animated:Bool) {

        super.viewWillAppear(animated);

        self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)

        self.navigationController?.navigationBar.shadowImage = UIImage()

    }

    override func viewDidDisappear(_animated:Bool) {

        super.viewDidDisappear(animated)

        self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)

        self.navigationController?.navigationBar.shadowImage = nil

    }

    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

    }

    //MARK:初始化方法

    private func initNavBar(){//导航栏

        let  leftItem :UIBarButtonItem=UIBarButtonItem(image:UIImage(named:"back"), style:UIBarButtonItemStyle.plain, target:self, action:#selector(navBack))

        self.navigationItem.leftBarButtonItem = leftItem

        self.navigationItem.title = "扫码"

    }

    private func initView(){//视图,权限

        self.view.backgroundColor = UIColor.black;

        if isCameraAviable() {

        }else{

            let alert:UIAlertController=UIAlertController(title:"提示", message:"没有相机权限", preferredStyle: .alert)

            let cancelAction :UIAlertAction=UIAlertAction(title:"取消", style: .cancel,handler:nil)

            let configAction :UIAlertAction=UIAlertAction(title:"去配置", style: .default, handler: {

                action in

                let urlObj = URL(string:UIApplicationOpenSettingsURLString)

                if#available(iOS10.0, *){

                    UIApplication.shared.open(urlObj!, options: [:], completionHandler:nil)

                }else{

                    UIApplication.shared.openURL(urlObj!)

                }

            })

            alert.addAction(cancelAction)

            alert.addAction(configAction)

            self.present(alert, animated:true, completion:nil)

            return

        }

    }

    private funcinitScanView(){//扫描视图

        scanView = YTScanQRCodeView(frame: CGRect(x:0, y: 0, width: scanViewSize, height: scanViewSize));

        scanView!.center = CGPoint(x: self.view.center.x, y: self.view.center.y-40)

        scanView!.bgColor = blueColor.cgColor

        scanView!.layer.cornerRadius = 4

        scanView!.layer.masksToBounds = true

        self.view.addSubview(scanView!)

        let scanLine:UILabel=UILabel(frame:CGRect(x: 10, y: 0, width:scanViewSize-20, height: 1))

        scanLine.backgroundColor = blueColor

        scanLine.tag= 99

        scanView?.addSubview(scanLine)

        let tipLabel:UILabel=UILabel(frame:CGRect(x: 0, y:self.view.center.y+100, width:self.view.frame.size.width, height: 20))

        tipLabel.font=UIFont.systemFont(ofSize: 14)

        tipLabel.textColor=UIColor.white

        tipLabel.textAlignment = NSTextAlignment.center

        tipLabel.text="请将二维码对准扫描框"

        self.view.addSubview(tipLabel);

        flashView = UIView(frame: CGRect(x:self.view.center.x-flashViewSize/2,y:self.view.frame.height-30-flashViewSize, width: flashViewSize, height: flashViewSize))

        flashView?.backgroundColor = grayColor

        flashView?.layer.cornerRadius = flashViewSize/2

        flashView?.layer.masksToBounds = true

        self.view.addSubview(flashView!)

        let tap : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(flashSwitch))

        flashView?.addGestureRecognizer(tap)

        let flashImg:UIImageView = UIImageView(frame: CGRect(x:flashViewSize/2-flashViewSize/6, y: flashViewSize/2-flashViewSize/6, width: flashViewSize/3, height: flashViewSize/3))

        flashImg.image=UIImage(named:"flashlight")

        flashView?.addSubview(flashImg)

    }

    privatefuncinitCaptureSession(){//多媒体,摄像头初始化

        session.sessionPreset = .high

        do{

            if let device : AVCaptureDevice = AVCaptureDevice.default(for: .video){

                letput =tryAVCaptureDeviceInput(device: device)

                ifsession.canAddInput(put) {

                    session.addInput(put)

                }

            }

        }catch  {

            print("初始化失败")

        }

        if session.inputs.count == 0 {

            letalert:UIAlertController=UIAlertController(title:"提示", message:"没有找到摄像头设备", preferredStyle: .alert)

            letcancelAction :UIAlertAction=UIAlertAction(title:"确定", style: .cancel,handler:nil)

            alert.addAction(cancelAction)

            self.present(alert, animated:true, completion:nil)

        }else{

            let out = AVCaptureMetadataOutput()

            out.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)

            out.rectOfInterest = self.scanView!.bounds

            ifsession.canAddOutput(out) {

                self.session.addOutput(out)

                let metaDataTypeList = [AVMetadataObject.ObjectType.qr,AVMetadataObject.ObjectType.code39,AVMetadataObject.ObjectType.ean13,AVMetadataObject.ObjectType.ean8,AVMetadataObject.ObjectType.code128,AVMetadataObject.ObjectType.code93,AVMetadataObject.ObjectType.pdf417,AVMetadataObject.ObjectType.interleaved2of5]

                out.metadataObjectTypes= metaDataTypeList

            }

            let previewLayer:AVCaptureVideoPreviewLayer=  AVCaptureVideoPreviewLayer(session: session)

            previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill

            previewLayer.frame=CGRect(x: 5, y: 5, width:scanViewSize-10, height:scanViewSize-10)

            scanView!.layer.insertSublayer(previewLayer, at: 0)

            session.startRunning()//开始扫描

            addScanAnimation()//开始动画

        }

    }

    //MARK :其他方法

    privatefuncisCameraAviable() ->Bool{

        let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)

        returnauthStatus != .restricted&& authStatus != .denied

    }

    privatefuncopenOrCloseTorch(){

        guard let device = AVCaptureDevice.default(for: AVMediaType.video) else {

            print("无法获取到您的设备")

            return

        }

        if device.hasTorch&& device.isTorchAvailable{

            try? device.lockForConfiguration()

            ifflashFlag{

                device.torchMode= .on

            }else{

                device.torchMode= .off

            }

        }

    }

    privatefuncaddScanAnimation(){

        letanimation :CABasicAnimation=CABasicAnimation(keyPath:"position.y")

        animation.fromValue=NSNumber(value: 10)

        animation.toValue=NSNumber(value:Float(scanViewSize)-10)

        animation.autoreverses=true

        animation.fillMode = kCAFillModeForwards

        animation.isRemovedOnCompletion = false

        animation.repeatCount=MAXFLOAT

        animation.duration= 2

        let label : UILabel = scanView?.viewWithTag(99) as! UILabel

        label.layer.add(animation, forKey:"scanAnimation")

    }

    private func removsScanAnimation(){

        let label : UILabel = scanView?.viewWithTag(99) as! UILabel

        label.layer.removeAnimation(forKey:"scanAnimation")

        label.isHidden=true

    }

    private func endScan(){

        if session.isRunning {

            session.stopRunning()

        }

        flashFlag=false

        openOrCloseTorch()

        removsScanAnimation()

    }

    //MARK:OC方法

    @objc func navBack(){

        self.navigationController?.popViewController(animated: true)

        endScan()//退出页面时,停止扫描,关闭闪光灯,关闭动画

    }

    @objc func flashSwitch(_tap:UIGestureRecognizer){

        ifflashFlag{

            flashView?.backgroundColor = grayColor

            if (flashView?.layer.sublayers?.count)! > 0 {

                letlayer :CALayer= (flashView?.layer.sublayers?.first)!

                layer.removeFromSuperlayer()

            }

            flashFlag=false

        }else{

            flashView?.layer.insertSublayer(self.gradientLayer, at: 0)

            flashFlag=true

        }

        //开启或关闭闪光灯

        openOrCloseTorch()

    }

}

extension YTScanVehicleViewController:AVCaptureMetadataOutputObjectsDelegate{

    func metadataOutput(_output:AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection:AVCaptureConnection) {

        ifmetadataObjects.count> 0 {

            endScan()//停止扫描

            let result : AVMetadataMachineReadableCodeObject = metadataObjects.first as! AVMetadataMachineReadableCodeObject

            ifletresultStr = result.stringValue{

                AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

                ifletresultClourse =self.scanResult{

                    resultClourse(0,resultStr)

                }

            }else{

                ifletresultClourse =self.scanResult{

                    resultClourse(1,"")

                }

            }

        }

    }

}

二维码扫描视图类

import UIKit

class YTScanQRCodeView:UIView{

    var bgColor:CGColor?

    override init(frame:CGRect) {

        super.init(frame: frame)

    }

    required  init?(coder aDecoder:NSCoder) {

        fatalError("init(coder:) has not been implemented")

    }

    override func draw(_rect:CGRect) {

        let cxt :CGContext = UIGraphicsGetCurrentContext()!

        letborderLineWidth :CGFloat  = 1

        letcornorLineWidth :CGFloat  = 12

        letcornorLength :CGFloat= 25

        cxt.setLineWidth(borderLineWidth)

        ifletbColor =bgColor{

            cxt.setStrokeColor(bColor)

        }

        cxt.addRect(self.bounds)

        cxt.strokePath()

        cxt.setLineWidth(cornorLineWidth)

        //左上角

        cxt.move(to:CGPoint(x: 0, y: 0))

        cxt.addLine(to:CGPoint(x: cornorLength, y: 0))

        cxt.strokePath()

        cxt.move(to:CGPoint(x: 0, y: 0))

        cxt.addLine(to:CGPoint(x: 0, y: cornorLength))

        cxt.strokePath()

        //右上角

        cxt.move(to:CGPoint(x:self.frame.size.width, y: 0))

        cxt.addLine(to:CGPoint(x:self.frame.size.width-cornorLength, y: 0))

        cxt.strokePath()

        cxt.move(to:CGPoint(x:self.frame.size.width, y: 0))

        cxt.addLine(to:CGPoint(x:self.frame.size.width, y:cornorLength ))

        cxt.strokePath()

        //右下角

        cxt.move(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))

        cxt.addLine(to:CGPoint(x:self.frame.size.width, y:self.frame.size.height-cornorLength))

        cxt.strokePath()

        cxt.move(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))

        cxt.addLine(to:CGPoint(x:self.frame.size.width-cornorLength, y:self.frame.size.height))

        cxt.strokePath()

        //左下角

        cxt.move(to:CGPoint(x:0, y:self.frame.size.height))

        cxt.addLine(to:CGPoint(x: 0, y:self.frame.size.height-cornorLength))

        cxt.strokePath()

        cxt.move(to:CGPoint(x: 0, y:self.frame.size.height))

        cxt.addLine(to:CGPoint(x:cornorLength, y:self.frame.size.height))

        cxt.strokePath()

    }

}

相关文章

网友评论

      本文标题:2018-07-28 swift 二维码扫描功能

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