【Swift】swift 扫描二维码 稳定快速准确各大APP均需要

转载地址:

swift 扫描二维码 稳定快速准确各大APP均需要

import UIKit
 
import AVFoundation
 
class ScanQrCodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
 
    //是否是第一次扫描到结果
    var firstResult: Bool = true
 
    //AVCaptureSession对象来执行输入设备和输出设备之间的数据传递
    var session: AVCaptureSession?
 
    //输入设备
    var videoInput: AVCaptureDeviceInput?
 
    //输出对象
    var metadataOutput: AVCaptureMetadataOutput = AVCaptureMetadataOutput()
 
    //预览图层
    var previewLayer: AVCaptureVideoPreviewLayer?
 
    var scanTimer: Timer?
 
    //边框
    lazy var borderView: UIImageView = UIImageView(image: UIImage(named: "ty_qrcode_bg"))
 
    //line
    lazy var scanLineView: UIImageView = UIImageView(image: UIImage(named: "ty_qrcode_line"))
 
    private let borderWidth: CGFloat = 400
 
    private let topMargin: CGFloat =  230
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        if !checkCameraAuth() {
            let alertController = UIAlertController(title: nil, message: "请在iphone的“设置-隐私-相机”选项中,允许应用访问你的相机", preferredStyle: .alert)
            let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: { _ in
                self.navigationController?.popViewController(animated: true)
            })
 
            let okAction = UIAlertAction(title: "前往", style: .default, handler: { _ in
                let settingUrl = NSURL(string: UIApplication.openSettingsURLString)!
                if UIApplication.shared.canOpenURL(settingUrl as URL) {
                    UIApplication.shared.openURL(settingUrl as URL)
                }
            })
 
            alertController.addAction(cancelAction)
            alertController.addAction(okAction)
            self.present(alertController, animated: true, completion: nil)
        }
 
        setupCaptureSession()
 
        addSubviews()
 
        scanTimer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(startAnimation), userInfo: nil, repeats: true)
    }
 
    override func viewWillAppear(_ animated: Bool) {
        firstResult = true
 
        if let session = self.session {
            session.startRunning()
        }
 
        scanTimer?.fireDate = NSDate.distantPast
    }
 
    func checkCameraAuth() -> Bool {
        let status = AVCaptureDevice.authorizationStatus(for: .video)
        let result = status == .authorized
        return  result
    }
 
    // MARK: - 生成背景遮盖
    func getCoverView(left: CGFloat, top: CGFloat) -> UIImage? {
        UIGraphicsBeginImageContext(CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height - 64))
 
        let contextRef = UIGraphicsGetCurrentContext()
 
        contextRef?.setFillColor(UIColor(red: 111/255.0, green: 111/255.0, blue: 22/255.0, alpha: 0.5).cgColor)
 
        contextRef?.fill(CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
 
        let inset: CGFloat = 4
 
        contextRef?.clear(CGRect(x: left + inset, y: top + inset, width: UIScreen.main.bounds.size.width - left * 2 - inset * 2, height: UIScreen.main.bounds.size.width - left * 2 - inset * 2))
 
        return UIGraphicsGetImageFromCurrentImageContext()
    }
 
    func addSubviews() {
        //扫描边框
        let borderViewY = (UIScreen.main.bounds.size.height-(self.view.center.x + 30))/2
        borderView.frame = CGRect.init(x: (UIScreen.main.bounds.size.width-(self.view.center.x+30))/2, y: borderViewY, width: self.view.center.x + 30, height: self.view.center.x + 30)
 
        view.addSubview(borderView)
 
        //扫描的线
        scanLineView.frame = CGRect(x:borderView.frame.origin.x+2, y:   borderView.frame.origin.y+2, width: borderView.bounds.size.width, height: 2)
 
        view.addSubview(scanLineView)
 
        print(borderView.frame.origin.x)
 
        print(scanLineView.frame)
 
        print(borderView.frame)
 
        let tipLabel = UILabel.init()
 
        tipLabel.text = "对准二维码,即可自动扫描"
 
        tipLabel.textColor = UIColor.white
 
        tipLabel.font = UIFont.systemFont(ofSize: 14)
 
        tipLabel.textAlignment = .center
 
        tipLabel.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
 
        tipLabel.center = CGPoint(x: borderView.center.x, y: borderView.center.y + (self.view.center.x + 30)/2 + 30)
 
        view.addSubview(tipLabel)
    }
 
    // MARK: - 开始扫描动画
    @objc func startAnimation() {
        //让约束从顶部开始
        var frame = self.scanLineView.frame
 
        frame.origin.y = borderView.frame.origin.y
 
        self.scanLineView.frame = frame
 
        self.scanLineView.layoutIfNeeded()
 
        UIView.animate(withDuration: 3.0, animations: {
            //改变frame
            frame.origin.y = self.borderView.frame.origin.y+self.borderView.bounds.size.height
 
            self.scanLineView.frame = frame
 
            //强制更新界面
            self.scanLineView.layoutIfNeeded()
        })
    }
 
    func stopAnimation() {
        //让约束从顶部开始
        var frame = self.scanLineView.frame
        frame.origin.y = 64 + topMargin
        self.scanLineView.frame = frame
        self.scanLineView.layoutIfNeeded()
        scanTimer?.invalidate()
        scanTimer = nil
    }
 
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        //关闭session
        if let session = self.session {
            session.stopRunning()
        }
    }
 
    deinit {
        scanTimer?.invalidate()
        scanTimer = nil
        print("scan-----deinit")
    }
 
    // MARK: - 设置session
    func setupCaptureSession() {
        self.session = AVCaptureSession()
        //高质量采集率
        self.session?.sessionPreset = AVCaptureSession.Preset.high
        guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return }
        //更改这个设置的时候必须先锁定设备,修改完后再解锁,否则崩溃
        do {
            try device.lockForConfiguration()
            //设置闪光灯为自动
            device.flashMode = AVCaptureDevice.FlashMode.auto
 
            device.unlockForConfiguration()
 
        } catch {
            print("崩溃")
        }
 
        do {
            try self.videoInput = AVCaptureDeviceInput(device: device)
        } catch {
            print("崩溃")
        }
 
        //输入设备
        if let videoInput = self.videoInput {
            if self.session?.canAddInput(videoInput) == true {
                self.session?.addInput(videoInput)
            }
        }

        //添加输出
        if self.session?.canAddOutput(self.metadataOutput) == true {
            self.session?.addOutput(self.metadataOutput)
        }
 
        self.metadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr,
                                                   AVMetadataObject.ObjectType.ean13,
                                                   AVMetadataObject.ObjectType.ean8,
                                                   AVMetadataObject.ObjectType.code128,
                                                   AVMetadataObject.ObjectType.code39,
                                                   AVMetadataObject.ObjectType.code93]
        self.metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)

        //预览图层
        if let session = self.session {
            self.previewLayer = AVCaptureVideoPreviewLayer(session: session)
            self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
            self.previewLayer?.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
        }
 
        if let layer = self.previewLayer {
            view.layer.insertSublayer(layer, at: 0)
        }
    }
    
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
 
        self.session?.stopRunning()
 
        if metadataObjects.count >= 1 {
 
            //数组中包含的都是AVMetadataMachineReadableCodeObject 类型的对象,该对象中包含解码后的数据
            let qrObject: AVMetadataMachineReadableCodeObject = metadataObjects.last as! AVMetadataMachineReadableCodeObject
 
            //拿到扫描内容在这里进行个性化处理
            let result = qrObject.stringValue
 
            print("result"+result!)
 
            //解析数据进行处理并实现相应的逻辑
 
            //代码省略
        }
    }
}

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页