美文网首页
Swift自定义扫描框并扫描二维码

Swift自定义扫描框并扫描二维码

作者: 向日葵的夏天_summer | 来源:发表于2018-11-16 16:04 被阅读0次
class ScanViewController: BaseViewController {

typealias FeelBarCodeViewScanSuccess = (_ brandName:String?,_ cosName:String?) -> Void
var scanSuccess:FeelBarCodeViewScanSuccess?

//是否是第一次扫描到结果
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:"scan_border"))
//line
lazy var scanLineView: UIImageView = UIImageView(image: UIImage(named: "scan_line"))

private let borderWidth = autoWidth(width: 400)
private let topMargin: CGFloat = autoHeight(height: 230)

override func viewDidLoad() {
    super.viewDidLoad()
    
    setupNav()
    setupCaptureSession()
    addSubviews()
    
    scanTimer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(startAnimation), userInfo: nil, repeats: true)

}

func setupNav() {
    navigationItem.title = "扫一扫"
    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "相册", style: .plain, target: self, action: #selector(albumAction))
}

//MARK:- 相册
@objc func albumAction() {
    Utils.isRightAlbum { [weak self] (authorized) in
        if authorized {
            let picker = UIImagePickerController()
            picker.sourceType = .photoLibrary
            picker.delegate = self
            picker.allowsEditing = false
            self?.present(picker, animated: true, completion: nil)
        }
    }
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    firstResult = true
    if let session = self.session {
        session.startRunning()
    }
    scanTimer?.fireDate = NSDate.distantPast
}

//MARK:- 扫描结果
func getInfoWithCode(code: String?) -> Void {
    if let url = code {
        scanTimer?.fireDate = NSDate.distantFuture
        
        let vc = AcquireBookViewController()
        if url.contains(BASE_URL) {
            vc.requestUrl = url
        } else {
            vc.isNotBookQR = true
        }
        navigationController?.pushViewController(vc, animated: true)
        
    }
}

func addSubviews() {
    let leftMargin: CGFloat = (SCREEN_WIDTH - borderWidth) * 0.5
    
    let coverImageView = UIImageView(frame: CGRect(x: 0, y: navigationHigh(), width: SCREEN_WIDTH, height: SCREEN_HEIGHT - navigationHigh()))
    coverImageView.backgroundColor = UIColor.clear
    coverImageView.image = self.getCoverView(left: leftMargin, top: topMargin)
    view.addSubview(coverImageView)
    
    //扫描边框
    borderView.frame = CGRect(x: leftMargin, y: navigationHigh() + topMargin, width: borderWidth, height: borderWidth)
    view.addSubview(borderView)
    
    //扫描的线
    scanLineView.frame = CGRect(x: leftMargin, y: navigationHigh() + topMargin, width: borderWidth, height: 2)
    view.addSubview(scanLineView)
    
    let tipLabel = UILabel.createLabelWith(title: "将取景框对准二维码,即可自动扫描", titleColor: UIColor.white, fontSize: autoFont(size: 24), alignment: .center, lines: 0)
    tipLabel.frame = CGRect(x: autoWidth(width: 40), y: borderView.frame.maxY + autoHeight(height: 40), width: SCREEN_WIDTH - autoWidth(width: 80), height: autoHeight(height: 40))
    view.addSubview(tipLabel)
}

//MARK:生成背景遮盖
func getCoverView(left: CGFloat, top: CGFloat) -> UIImage? {
    UIGraphicsBeginImageContext(CGSize(width: SCREEN_WIDTH, height: SCREEN_HEIGHT - navigationHigh()))
    let contextRef = UIGraphicsGetCurrentContext()
    contextRef?.setFillColor(Main_TextBlackColor.withAlphaComponent(0.3).cgColor)
    contextRef?.fill(CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT))
    let inset = autoWidth(width: 4)
    contextRef?.clear(CGRect(x: left + inset, y: top + inset, width: SCREEN_WIDTH - left * 2 - inset * 2, height: SCREEN_WIDTH - left * 2 - inset * 2))
    return UIGraphicsGetImageFromCurrentImageContext()
}

//MARK:- 开始扫描动画
@objc func startAnimation() -> Void {
    
    //让约束从顶部开始
    var frame = self.scanLineView.frame
    frame.origin.y = navigationHigh() + topMargin
    self.scanLineView.frame = frame
    self.scanLineView.layoutIfNeeded()
    
    UIView.animate(withDuration: 3.0, animations: {
        //改变frame
        frame.origin.y = navigationHigh() + self.topMargin + self.borderWidth
        self.scanLineView.frame = frame
        //强制更新界面
        self.scanLineView.layoutIfNeeded()
    })
}

func stopAnimation() -> Void {
    //让约束从顶部开始
    var frame = self.scanLineView.frame
    frame.origin.y = navigationHigh() + topMargin
    self.scanLineView.frame = frame
    self.scanLineView.layoutIfNeeded()
    
    scanTimer?.invalidate()
    scanTimer = nil
}

//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: SCREEN_WIDTH, height: SCREEN_HEIGHT)
    }
    
    if let layer = self.previewLayer {
        view.layer.insertSublayer(layer, at: 0)
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    //关闭session
    if let session = self.session{
        session.stopRunning()
    }
    
}

deinit {
    scanTimer?.invalidate()
    scanTimer = nil
    print("scan-----deinit")
}

}

extension ScanViewController: AVCaptureMetadataOutputObjectsDelegate {

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

    for current in metadataObjects {
        if current.isKind(of: AVMetadataMachineReadableCodeObject.self) {
            
            let code = current as! AVMetadataMachineReadableCodeObject
            //码内容
            if let codeContent = code.stringValue {
                if firstResult == true {
                    session?.stopRunning()
                    //                        scanTimer?.invalidate()
                    //                        scanTimer = nil
                    getInfoWithCode(code: codeContent)
                }
                firstResult = false
            }

        }
    }
}

}

extension ScanViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    
    let type = info[UIImagePickerControllerMediaType] as? String
    if type == "public.image" {
        if let image = info["UIImagePickerControllerOriginalImage"] as? UIImage {
            getInfoWithImage(image: image)
        }
    }
    
    picker.dismiss(animated: true, completion: nil)
}

//MARK:- 解析图片
func getInfoWithImage(image: UIImage) {
    
    let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
    
    let features = detector?.features(in: CIImage(cgImage: image.cgImage!))
    if features == nil || features!.count <= 0 {
        dm_toast("没有可识别的二维码")
        return
    }
    
    for feature in features! {
        if let qrcode = feature as? CIQRCodeFeature {
            getInfoWithCode(code: qrcode.messageString)
        }
    }
}
}

相关文章

网友评论

      本文标题:Swift自定义扫描框并扫描二维码

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