最近项目有需求, 本来打算用ZXing-Objc来做, 经理说用原生做更好一些, 就去度娘找了一些iOS原生二维码条码扫描代码, 封装了一下
最初的时候确实也没有在子线程中做, 所有代码都放在一起, 后来发现二维码设备的初始化是一个很耗时的操作, 页面跳转卡顿, 影响用户体验.
废话不多说, 直接贴代码
dispatch_async(dispatch_get_global_queue(0, 0)) { // 初始化二维码扫描设备 capture.initDevice() dispatch_async(dispatch_get_main_queue(), { // 添加遮罩 capture.initUI(capture.scanRect, complete: capture.scanComplete) if loadComplete != nil { capture.loadComplete!(capture) } }) }
下面是对设备的初始化
// MARK: - 设备初始化 private func initCaptureDevice() { // Device : 已经初始化过 // Input do { try input = AVCaptureDeviceInput(device: device) } catch { print(error) } // OutPut output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue()) // Session session.sessionPreset = AVCaptureSessionPresetHigh if session.canAddInput(input) { session.addInput(input) } if session.canAddOutput(output) { session.addOutput(output) } // 一般这几种条码扫描就够用 output.metadataObjectTypes = [ AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeQRCode ] let rect = CGRect( x: rectTopView.size.height/screenHeight, y: (screenWidth-rectLeftView.size.width-scanRect.size.width)/screenWidth, width: scanRect.size.height/screenHeight, height: scanRect.size.width/screenWidth ) output.rectOfInterest = rect // Preview preview = AVCaptureVideoPreviewLayer(session: session) preview.videoGravity = AVLayerVideoGravityResizeAspectFill preview.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight) self.layer.insertSublayer(preview, atIndex: 0) session.startRunning() }
这里值得说的是上方代码的32行部分, 这里是设置扫码响应区域, 也就是限制扫码区域.
它接收的是以右上角为(0, 0)点, 宽高接受的是宽高所占屏幕宽高的比例, 并且横纵坐标是颠倒的, 可能大家并很明白这句话什么意思, 进一步解释就是以右上角为(0,0)点, 扫码区域高度除以屏幕高度作为宽, 扫码区域宽度除以屏幕宽度作为高,所以它最终的值为CGRect(y/ScreenHeight, (ScreenWidth - leftPadding - scanWidth)/ScreenWidth, height/ScreenHeight, width/ScreenWidth), 这样就限制了它的扫码区域为一个固定的位置
具体代码的github地址:
暴露了一些接口, 遮罩部分没有想到什么好的方法,用了四个View来做的
https://github.com/billowsDown/QNCapture