Swift二維碼掃描實現(xiàn)(自定義UI)

前不久有網(wǎng)友跟我說,demo有bug不能運行,所以抽空改了一下,主要原因是swift版本問題,當初我寫這個demo的時候是Swift3.0 貝塔版,所以有些語法上的更新。

在過去的WWDC2016中,Apple Inc推出了新版Swift--Swift3.0;對于Swift3.0的語法什么的,在此就不聊了,畢竟人家還是個小白。

Apple Inc WWDC2016

書歸正傳,iOS7.0以前要使用二維碼掃描功能,需要借助兩大開源的組件ZBar和ZXing來實現(xiàn),自iOS7.0之后可以使用自帶的AVFoundation框架實現(xiàn)二維碼掃描,而且效率更高。

因此實現(xiàn)二維碼掃描首先需要導(dǎo)入AVFoundation框架

  • 1 導(dǎo)入AVFoundation框架
import AVFoundation
  • 2 創(chuàng)建視圖預(yù)覽顯示并設(shè)置想實現(xiàn)的UI效果
//屏幕掃描區(qū)域視圖
 //屏幕掃描區(qū)域視圖
    let barcodeView = UIView(frame: CGRect(x: UIScreen.main.bounds.size.width * 0.2, y: UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width * 0.6, height: UIScreen.main.bounds.size.width * 0.6))
    //掃描線
    let scanLine = UIImageView()
    
    var scanning : String!
    var timer = Timer()
 
  override init(frame: CGRect) {
    super.init(frame: frame)
  barcodeView.layer.borderWidth = 1.0
        barcodeView.layer.borderColor = UIColor.white.cgColor
        self.addSubview(barcodeView)
        
        //設(shè)置掃描線
        scanLine.frame = CGRect(x: 0, y: 0, width: barcodeView.frame.size.width, height: 5)
        scanLine.image = UIImage(named: "QRCodeScanLine")
        
        //添加掃描線圖層
        barcodeView.addSubview(scanLine)
        
        self.createBackGroundView()
        
        self.addObserver(self, forKeyPath: "scanning", options: .new, context: nil)
        
        timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(moveScannerLayer(_:)), userInfo: nil, repeats: true)
  }
  • 3 實現(xiàn)背景灰色半透明,分四個View,設(shè)置所需要實現(xiàn)的樣式;同樣的也可以采用重寫drawRect方法來實現(xiàn)。
func createBackGroundView() {
   let topView = UIView(frame: CGRect(x: 0, y: 0,  width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height * 0.35))
        let bottomView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.size.width * 0.6 + UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height * 0.65 - UIScreen.main.bounds.size.width * 0.6))
        
        let leftView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width * 0.2, height: UIScreen.main.bounds.size.width * 0.6))
        let rightView = UIView(frame: CGRect(x: UIScreen.main.bounds.size.width * 0.8, y: UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width * 0.2, height: UIScreen.main.bounds.size.width * 0.6))
        
        topView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        bottomView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        leftView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        rightView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        
        let label = UILabel(frame: CGRect(x: 0, y: 10, width: UIScreen.main.bounds.size.width, height: 21))
        label.textAlignment = .center
        label.font = UIFont.systemFont(ofSize: 14)
        label.textColor = UIColor.white
        label.text = "將二維碼/條形碼放入掃描框內(nèi),即自動掃描"
        
        bottomView.addSubview(label)
        
        
        self.addSubview(topView)
        self.addSubview(bottomView)
        self.addSubview(leftView)
        self.addSubview(rightView)
  }
  • 4 在初始化視圖的時候添加觀察者,用于實現(xiàn)暫停掃描時,掃描線停止?jié)L動
self.addObserver(self, forKeyPath: "scanning", options: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        if scanning == "start" {
            timer.fire()
        }else{
            timer.invalidate()
        }
    }
  • 5 掃描線滾動動畫
//讓掃描線滾動
  func moveScannerLayer(_ timer : Timer) {
    scanLine.frame = CGRect(x: 0, y: 0, width: self.barcodeView.frame.size.width, height: 12)
    UIView.animate(withDuration: 2) {
      self.scanLine.frame = CGRect(x: self.scanLine.frame.origin.x, y: self.scanLine.frame.origin.y + self.barcodeView.frame.size.height - 10, width: self.scanLine.frame.size.width, height: self.scanLine.frame.size.height) 
    }
  }
  • 6 聲明背景視圖
//相機顯示視圖
    let cameraView = ScannerBackgroundView(frame: UIScreen.main.bounds)
  • 7 初始化捕捉設(shè)備、創(chuàng)建捕捉會話、輸入媒體類型、設(shè)置代理等
    let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
   
    let input :AVCaptureDeviceInput
   
    let output = AVCaptureMetadataOutput()
   
    //捕捉異常,并處理異常
    do{
      input = try AVCaptureDeviceInput(device: captureDevice)
      captureSession.addInput(input)
      captureSession.addOutput(output)
    }catch {
      print("異常")
    }
    let dispatchQueue = DispatchQueue(label: "queue", attributes: [])
    output.setMetadataObjectsDelegate(self, queue: dispatchQueue)
    output.metadataObjectTypes = NSArray(array: [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]) as [AnyObject]
    let videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
   
    videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
   
    videoPreviewLayer?.frame = cameraView.bounds
   
    cameraView.layer.insertSublayer(videoPreviewLayer!, at: 0)

    output.rectOfInterest = CGRect(x: 0.2, y: 0.2, width: 0.6, height: 0.6)
  • 8 掃描結(jié)果處理(根據(jù)不同掃描結(jié)果,執(zhí)行不同的操作)
 if metadataObjects != nil && metadataObjects.count > 0 {
            let metaData : AVMetadataMachineReadableCodeObject = metadataObjects.first as! AVMetadataMachineReadableCodeObject
            
            print(metaData.stringValue)
            
            DispatchQueue.main.async(execute: {
                let result = WebViewController()
                result.url = metaData.stringValue
                
                self.navigationController?.pushViewController(result, animated: true)
            })
            captureSession.stopRunning()
        }
  • 9 從相冊中獲取二維碼圖片進行識別,在此需要判斷相冊中獲取的圖片是否具有二維碼信息
let image = info[UIImagePickerControllerOriginalImage]
   
    let imageData = UIImagePNGRepresentation(image as! UIImage)
   
    let ciImage = CIImage(data: imageData!)
   
    let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyLow])
   
    let array = detector?.features(in: ciImage!)
   
    let result : CIQRCodeFeature = array!.first as! CIQRCodeFeature
   
   
    let resultView = WebViewController()
    resultView.url = result.messageString
   
    self.navigationController?.pushViewController(resultView, animated: true)
    picker.dismiss(animated: true, completion: nil)

歐了,所有工作都已完成;由于本人是個菜鳥,思路僅供參考,如果有更好的思路,歡迎交流。
附上:
demo地址:demo下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,180評論 4 61
  • 做這個夢的時候,我還住在村里。 在夢里,日軍夜襲村子,大家都被抓了,只有我和桑同學(xué)逃脫。我和她穿過果林,橫亙在眼前...
    小豆汁閱讀 220評論 0 0
  • 今日心享~享受家人 家人,是我靈魂的碎片,也是我溫暖的連接! 我享受家人,他們充滿著無限的歡笑與樂趣! 我享受爸爸...
    吸引力修煉閱讀 576評論 0 3
  • 幾年前看的一部日本電影《被嫌棄的松子的一生》,不知道有多少人看過。 當時的關(guān)注點并不在這句話,那時還小,沒有步入社...
    向像象閱讀 461評論 1 1
  • 文|故鄉(xiāng)的云 時光匆匆,還記得2016年的8月18日,那是我第一次踏入大學(xué)校園的日子,當時的我和現(xiàn)在的大一新生...
    故鄉(xiāng)的云wj閱讀 1,740評論 0 2