1. 程式人生 > >【Swift】原生二維碼掃描

【Swift】原生二維碼掃描

import UIKit
import AVFoundation
protocol ScanViewDelegate: NSObjectProtocol{
    /// 掃碼資料
    ///
    /// - Parameter pileCode: 編碼
    func captureOutputSuccess(pileCode:String);
}
class ScanView: UIView,AVCaptureMetadataOutputObjectsDelegate {
    /// 建立裝置
    var captureDevice = AVCaptureDevice.defaultDevice
(withMediaType: AVMediaTypeVideo) /// 捕獲視訊 var captureSession : AVCaptureSession? /// 捕獲視訊的預覽層 var videoPreviewLayer : AVCaptureVideoPreviewLayer? /// 提示文字 var titleLabel = UILabel() /// 圖片 var quJingImage:UIImageView! var saoMaTiaoImage : UIImageView? /// 開燈 var openLampButton:UIButton! // 代理 weak var delegate : ScanViewDelegate! /// 元資料輸出 let captureMetadataOutput = AVCaptureMetadataOutput() override init(frame: CGRect) { super.init
(frame: frame) createQrView() createScanPanelView() } /// 建立掃描裝置 func createQrView(){ let authStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) if authStatus == AVAuthorizationStatus.restricted || authStatus == AVAuthorizationStatus.denied
{ DZAlertView.sharedInstance.show(DZAlertViewType.blackViewAndClickDisappear, contentType: DZAlertContentViewType.warning, message: ["請在iPhone的“設定”-“隱私”-“相機”功能中,找到“\(Bundle.main.appDisplayName)”開啟相機訪問許可權"]) return } //給裝置新增input輸入 var input : AnyObject! do{ input = try AVCaptureDeviceInput(device: captureDevice) }catch{ } if input == nil { return } captureSession = AVCaptureSession() captureSession?.addInput(input as! AVCaptureInput) captureSession?.addOutput(captureMetadataOutput) captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) captureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode] /// 顯示的layer videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) let isphone = UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.phone ? true : false if isphone { videoPreviewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait }else{ videoPreviewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.landscapeRight } videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill videoPreviewLayer?.frame = self.layer.bounds self.layer.addSublayer(videoPreviewLayer!) captureSession?.startRunning() } /// 建立掃描面板 func createScanPanelView(){ //提示文字 self.addSubview(titleLabel) titleLabel.snp.makeConstraints { (make) -> Void in make.top.equalTo(UIConfigure.Width / 750 * 45) make.left.equalTo(40) make.right.equalTo(-40) } titleLabel.numberOfLines = 0 titleLabel.textAlignment = NSTextAlignment.center titleLabel.text = "將二維碼放入框中即可自動掃描" titleLabel.textColor = UIColor.white titleLabel.font = UIConfigure.Font14 // 取景框圖片 quJingImage = UIImageView(image: BaseImage(named: "QSD_Scan_ScanQr")?.image) self.addSubview(quJingImage) quJingImage.snp.makeConstraints { (make) -> Void in make.top.equalTo(titleLabel.snp.bottom).offset(UIConfigure.Width / 750 * 30 * UIConfigure.SizeScale) make.centerX.equalTo(self.snp.centerX) make.width.equalTo(220 * UIConfigure.SizeScale) make.height.equalTo(220 * UIConfigure.SizeScale) } self.layoutIfNeeded() print(CGRect(x: quJingImage.frame.origin.x / UIConfigure.Width, y: quJingImage.frame.origin.y / (UIConfigure.Height - 64), width: quJingImage.frame.size.width / UIConfigure.Width, height: quJingImage.frame.size.height / (UIConfigure.Height - 64))) // captureMetadataOutput.rectOfInterest = CGRect(x: quJingImage.frame.origin.x / UIConfigure.Height, y: quJingImage.frame.origin.y / UIConfigure.Width, width: quJingImage.frame.size.width / UIConfigure.Width, height: quJingImage.frame.size.height / UIConfigure.Width) // 上下左右四個遮蓋黑邊 let topView = UIView() self.addSubview(topView) topView.snp.makeConstraints { (make) -> Void in make.top.equalTo(0) make.left.equalTo(0) make.right.equalTo(0) make.bottom.equalTo(quJingImage.snp.top) } topView.backgroundColor = UIColor.black topView.alpha = 0.3 let leftView = UIView() self.addSubview(leftView) leftView.snp.makeConstraints { (make) -> Void in make.top.equalTo(topView.snp.bottom) make.left.equalTo(0) make.right.equalTo(quJingImage.snp.left) make.bottom.equalTo(0) } leftView.backgroundColor = UIColor.black leftView.alpha = 0.3 let rightView = UIView() self.addSubview(rightView) rightView.snp.makeConstraints { (make) -> Void in make.top.equalTo(topView.snp.bottom) make.left.equalTo(quJingImage.snp.right) make.right.equalTo(0) make.bottom.equalTo(0) } rightView.backgroundColor = UIColor.black rightView.alpha = 0.3 let bottomView = UIView() self.addSubview(bottomView) bottomView.snp.makeConstraints { (make) -> Void in make.top.equalTo(quJingImage.snp.bottom) make.left.equalTo(leftView.snp.right) make.right.equalTo(rightView.snp.left) make.bottom.equalTo(0) } bottomView.backgroundColor = UIColor.black bottomView.alpha = 0.3 self.bringSubview(toFront: titleLabel) //掃描條不斷動的那個 saoMaTiaoImage = UIImageView(image: BaseImage(named: "QSD_Scan_ScanQrLIne")?.image) self.addSubview(saoMaTiaoImage!) saoMaTiaoImage!.snp.makeConstraints { (make) -> Void in make.top.equalTo(quJingImage.snp.top) make.centerX.equalTo(quJingImage.snp.centerX) make.width.equalTo(200 * UIConfigure.SizeScale) make.height.equalTo(1) } saoMaTiaoImage?.isHidden = false changeStyle() //閃光燈按鈕 openLampButton = UIButton() self.addSubview(openLampButton) openLampButton.snp.makeConstraints { (make) -> Void in make.top.equalTo(quJingImage.snp.bottom).offset(UIConfigure.Width / 750 * 15 * UIConfigure.SizeScale) make.left.equalTo(quJingImage.snp.left) make.right.equalTo(quJingImage.snp.right) make.height.equalTo(UIConfigure.SimallButtonHeight) } openLampButton.setTitle("開燈", for: UIControlState.normal) openLampButton.setTitle("關燈", for: UIControlState.selected) openLampButton.addTarget(self, action: #selector(ScanView.openShanGuang(sender:)), for: UIControlEvents.touchUpInside) openLampButton.setTitleColor(UIConfigure.ThemeColor, for: UIControlState.normal) openLampButton.titleLabel?.textColor = UIConfigure.ThemeColor openLampButton.backgroundColor = UIColor.white openLampButton.layer.cornerRadius = UIConfigure.CornerRadius openLampButton.layer.masksToBounds = true openLampButton.layer.borderColor = UIConfigure.ThemeColor.cgColor openLampButton.layer.borderWidth = 0.5 } /** 掃描條不斷的移動 */ func changeStyle(){ guard self.saoMaTiaoImage != nil else { return } self.saoMaTiaoImage?.isHidden = false UIView.animate(withDuration: 3.5, animations: { [weak self] () -> Void in if(self != nil){ self!.saoMaTiaoImage?.transform = CGAffineTransform(translationX: 0, y: 220 * UIConfigure.SizeScale) } }) { [weak self](end) -> Void in if(self != nil){ UIView.animate(withDuration: 3.5, animations: { [weak self] in if(self != nil){ self!.saoMaTiaoImage?.transform = CGAffineTransform.identity } }, completion: { [weak self](end) in if self != nil { self!.changeStyle() } }) } } } /// 開閃光 func openShanGuang(sender:UIButton){ sender.isSelected = !sender.isSelected if captureDevice != nil && captureDevice!.hasFlash && captureDevice!.hasTorch { do { try captureDevice?.lockForConfiguration() if sender.isSelected { captureDevice!.flashMode = AVCaptureFlashMode.on captureDevice!.torchMode = AVCaptureTorchMode.on }else{ captureDevice!.flashMode = AVCaptureFlashMode.off captureDevice!.torchMode = AVCaptureTorchMode.off } captureDevice?.unlockForConfiguration() }catch{ } }else{ DZAlertView.sharedInstance.show(DZAlertViewType.blackViewAndClickDisappear, contentType: DZAlertContentViewType.warning, message: ["不能開啟裝置的閃光燈"]) } } func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { if metadataObjects == nil || metadataObjects.count == 0 { return } playSoundEffect(name: "Qcodesound.caf") let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject if metadataObj.type == AVMetadataObjectTypeQRCode { if metadataObj.stringValue != nil { captureSession?.stopRunning() print("剛剛掃描出來!!!\(metadataObj.stringValue)") delegate.captureOutputSuccess(pileCode: metadataObj.stringValue!) } } } /// 掃描成功後播放聲音 /// /// - Parameter name: 地址 func playSoundEffect(name : String){ let audioFile = Bundle.main.path(forResource: name, ofType: nil) let fileUrl = URL(fileURLWithPath: audioFile!) var soundID : SystemSoundID = 0 AudioServicesCreateSystemSoundID(fileUrl as CFURL, &soundID) AudioServicesAddSystemSoundCompletion(soundID, nil, nil, { (SounID, clientData) in print("播放完成") }, nil) AudioServicesPlaySystemSound(soundID) } deinit { print("掃描銷燬") } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }