ios使用AVFoundation自定义实现扫码功能

2 篇文章 0 订阅
1 篇文章 0 订阅


使用AVFoundation实现扫码读取二维码数据,界面定义使用SnapKit自动布局框架实现。

自定义界面

在controller的viewDidLoad方法中绘制界面组件。
		self.title = "二维码/条码"
        self.view.backgroundColor = UIColor.black
        self.cameraView = UIView()
        self.cameraView.backgroundColor = UIColor.clear
        self.view.addSubview(self.cameraView)
        self.cameraView.snp.makeConstraints { (make) in
          make.top.left.right.bottom.equalTo(0)
        }
      
        self.scanView = UIView()
        self.scanView.backgroundColor = UIColor.clear
        self.view.addSubview(self.scanView)
        self.scanView.snp.makeConstraints { (make) in
          make.centerY.equalTo(self.view.snp.centerY).offset(-20)
          make.centerX.equalTo(self.view.snp.centerX)
          make.width.height.equalTo(200)
        }
      
      
        let tipLabl = UILabel()
        tipLabl.font = UIFont.systemFont(ofSize: 14)
        tipLabl.textColor = UIColor.white
        tipLabl.textAlignment = .center
        tipLabl.numberOfLines = 0
        tipLabl.alpha = 1
        tipLabl.text = "将二维码/条形码放入框内,即可自动扫描"
      
        self.scanLine = UIView()
        self.scanLine.backgroundColor = CommonUtil.colorWithRGB(rgb: 0x2B4B6C, a: 1)
        self.view.addSubview(self.scanLine)
        self.scanLine.snp.makeConstraints { (make) in
          make.top.equalTo(self.scanView.top)
          make.left.right.equalTo(self.scanView)
          make.width.equalTo(self.scanView.snp.width)
          make.height.equalTo(1)
        }
      
        let topBg = UIView()
        topBg.backgroundColor = UIColor.black
        topBg.alpha = 0.8
        self.view.addSubview(topBg)
        topBg.snp.makeConstraints { (make) in
          make.top.equalTo(0)
          make.centerX.equalTo(self.view)
          make.bottom.equalTo(self.scanView.snp.top)
          make.width.equalTo(self.scanView.snp.width)
        }
      
        let bottomBg = UIView()
        bottomBg.backgroundColor = UIColor.black
        bottomBg.alpha = 0.8
        self.view.addSubview(bottomBg)
        bottomBg.snp.makeConstraints { (make) in
          make.centerX.equalTo(self.view)
          make.top.equalTo(self.scanView.snp.bottom)
          make.bottom.equalTo(0)
          make.width.equalTo(self.scanView.snp.width)
          
        }
      
        let leftView = UIView()
        leftView.backgroundColor = UIColor.black
        leftView.alpha = 0.8
        self.view.addSubview(leftView)
        leftView.snp.makeConstraints { (make) in
          make.top.bottom.equalTo(0)
          make.left.equalTo(0)
          make.right.equalTo(self.scanView.snp.left)
        }
      
        let rightView = UIView()
        rightView.backgroundColor =  UIColor.black
        rightView.alpha = 0.8
        self.view.addSubview(rightView)
        rightView.snp.makeConstraints { (make) in
          make.top.bottom.equalTo(0)
          make.left.equalTo(self.scanView.snp.right)
          make.right.equalTo(0)
        }
      
        self.view.addSubview(tipLabl)
        tipLabl.snp.makeConstraints { (make) in
          make.top.equalTo(self.scanView.snp.bottom).offset(10)
          make.height.greaterThanOrEqualTo(20)
          make.left.right.equalTo(self.scanView)
        }

初始化相机

在viewDidAppear检查权限、初始化相机、开启界面动画效果

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    if !self.iniLogic {
      self.iniLogic = true
      self.initAuthorization()
    }
    captureSession.startRunning()
    self.startAnimate()
  }
func initAuthorization() {
    if CommonAuthorizationUtils.getInstance().authorizationDeviceStatus(mediaType: AVMediaType.video.rawValue) {
      self.initCamera()
      captureSession.startRunning()
    }else{
      self.backBtnClick()
    }
  }
  
func initCamera() {
    let metadataOutput:AVCaptureMetadataOutput = AVCaptureMetadataOutput()
    let input:AVCaptureDeviceInput
    do {
      input =  try AVCaptureDeviceInput(device: self.captureDevice)
    }catch{
      self.showWithError(message: "初始化失败")
      return
    }
    if captureSession.canAddInput(input) {
      captureSession.addInput(input)
    }
    if captureSession.canAddOutput(metadataOutput) {
      captureSession.addOutput(metadataOutput)
      metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
      metadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr,AVMetadataObject.ObjectType.code39,AVMetadataObject.ObjectType.code93,AVMetadataObject.ObjectType.code128,AVMetadataObject.ObjectType.code39Mod43,AVMetadataObject.ObjectType.ean13,AVMetadataObject.ObjectType.ean8]
    }
    let layer = AVCaptureVideoPreviewLayer(session: captureSession)
    layer.videoGravity = AVLayerVideoGravity.resizeAspectFill
    layer.frame = self.view.layer.bounds
    let scanx = self.scanView.left/self.view.width
    let scany = self.scanView.top/self.view.height
    let scanWidth = self.scanView.width/self.view.width
    let scanHeight = self.scanView.height/self.view.height
    let scanRect = CGRect(x: scany, y: scanx, width: scanHeight, height: scanWidth)
    metadataOutput.rectOfInterest = scanRect
    self.cameraView.layer.insertSublayer(layer, at: 1)
  }

界面动画

func startAnimate() {
    self.scanLine.isHidden = false
    if self.timer == nil {
      self.timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
      self.timer?.scheduleRepeating(deadline: .now(), interval: .seconds(2))
      self.timer?.setEventHandler(handler: {
        self.moveScanLine()
      })
    }
    self.startTimer()
  }
  
  func moveScanLine() {
    self.scanLine.top = self.scanView.top
    UIView.animate(withDuration: 2, animations: {
      self.scanLine.top = self.scanView.bottom
    })
  }
  
  func startTimer() {
    self.timer?.resume()
  }
  
  func stopTimer() {
    self.scanLine.top = self.scanView.top
    self.scanLine.isHidden = true
    self.timer?.cancel()
    self.timer = nil
  }

实现AVCaptureMetadataOutputObjectsDelegate代理,获取扫码结果

extension QrScanVC:AVCaptureMetadataOutputObjectsDelegate{
  func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
    self.playTip()
    self.stopTimer()
    self.captureSession.stopRunning()
    if let data = metadataObjects.first as? AVMetadataMachineReadableCodeObject {
      self.didScanResult?(data.stringValue ?? "")
      self.backBtnClick()
    }
  }
}

扫码成功播放提示音

func playTip() {
    //        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
    do {
      if let path = Bundle.main.path(forResource: "scan_done", ofType: "mp3"){
        self.avAudioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
        self.avAudioPlayer?.delegate = self
        self.avAudioPlayer?.volume = 1
        self.avAudioPlayer?.numberOfLoops = 1
        self.avAudioPlayer?.prepareToPlay()
        self.avAudioPlayer?.play()
      }
    }catch {
      debugPrint("play audio error")
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值