iOS原生扫码(ADQRcodeScanView)

参考文章:
http://stackoverflow.com/questions/32401364/how-do-i-use-the-metadataoutputrectofinterestforrect-method-and-rectofinterest-p
http://www.jianshu.com/p/3fb24fc7b415
项目地址:https://github.com/tiancanfei/ADQRScanView.git
iOS原生扫码使用还是很方便的,只不过是iOS7以后的技术,最近用到把一些注意事项和踩过的坑记录下
iOS原生扫码的实现就是构建一个扫描回话(session),完成一次扫码过程就是完成一次会话(从会话的开启到会话结束)。
一、扫描会话构建
1、获取扫描设备
扫描必然用到摄像头,我们需要获取摄像头
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
2、创建设备输入和设备输出

//将设备设置为输入设备
self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
 //创建设备输出 
self.output = [[AVCaptureMetadataOutput alloc]init];`

3、设置输出代理(AVCaptureMetadataOutputObjectsDelegate)
代理只有一个方法需要实现其作用就是扫码成功的回调(- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection)

//设置设备代理和执行线程 
[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];

4、创建扫描会话,并且将设备的输入和输出添加到会话
会话是输入和输出的桥梁,只有将设备输出和输入加入到会话设备才能正常工作

//创建会话 
self.session = [[AVCaptureSession alloc]init];
//设置视频输入每一帧图像质量
 [self.session setSessionPreset:AVCaptureSessionPreset1920x1080];
//添加设备输入到会话
 if ([self.session canAddInput:self.input]) 
{ 
    [self.session addInput:self.input]; 
} 
//添加设备输出到会话 
if ([self.session canAddOutput:self.output]) 
{
    [self.session addOutput:self.output];
}

5、设置扫码类型

//设置识别二维码或者条码,这里可以识别二维码和条形码
(只有AVMetadataObjectTypeQRCode是二维码,其他常量都是条码) 
self.output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeCode39Code,AVMetadataObjectTypeCode128Code,AVMetadataObjectTypeCode39Mod43Code,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode93Code];

6、设置预览框(就是那个半透明的背景框)

//给会话创建设置预览框(就是可视范围) 
self.preview =[AVCaptureVideoPreviewLayer layerWithSession:self.session]; 
self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill; 
[self.layer insertSublayer:self.preview atIndex:0];

7、开启扫描会话

//开始扫描 
[self.session startRunning];

到此,其实已经可以扫码了。
二、扫描范围限制
以上虽然实现了扫码功能,但是到底是比较粗糙,下面做一些改善。
通常我们看到诸如微信等的扫码都会有一个扫码框,只有在扫描范围内才能扫描成功,这就是扫描范围的限制,可以让扫描更加方便。当然,限制扫描范围绝对不仅仅是为了扫描方便,更重要一点是优化性能,设置扫描范围,设备在捕获信息的时候需要处理的图像就会小一点,处理起来自然速度回比较快。但是如何限制扫描范围确实让我头疼了一段时间,几经波折呀,最后找到了上面的标注的两篇文章才正真解决了。
扫描范围的限制其实只需要设置输出设备的rectOfInterest属性,而这个属性的值是一个CGRect而且x,y,w,h的取值都在0~1之间是一个比例,查阅了很多博客,最后发现只有下面的方法最靠谱,感觉也最正规,就是调用系统官方提供的metadataOutputRectOfInterestForRect方法,那种使用手动计算比例的方法,一旦改变预览框(preview)的frame(默认的预览框都是全屏幕的),就不怎么好使了,也许是我没有理解吧。

//计算有效的扫描范围 
CGRect rectOfInterest = [self.preview metadataOutputRectOfInterestForRect:visibleRect]; 
//限制有效的扫描范围
 [self.output setRectOfInterest:rectOfInterest];

三、预览框设置(半透明背景框)
通常我们看到的扫描框都是周边是半透明的,只有有效扫描范围内才是可以去透明的。其实办法简单就是给预览框(preview)加一个遮盖并且把有效扫描范围的rect挖空即可。
办法直接上代码

#pragma mark 设置背景
- (void)setPreviewBackground{
    if (self.previewBackgroundSetted) {
        return;
    }
    self.previewBackgroundSetted = YES;
    CALayer *coverLayer = [[CALayer alloc] init];
    coverLayer.frame = self.bounds;
    coverLayer.backgroundColor = [kScanViewBackgroundColor colorWithAlphaComponent:kBackgroundOpacity].CGColor;
    [self.preview addSublayer:coverLayer];
    
    UIBezierPath *outerBorderPath = [UIBezierPath bezierPathWithRect:self.bounds];
    
    UIBezierPath *innderBorderPath = [UIBezierPath bezierPathWithRect:self.visibleRect];
    
    [outerBorderPath appendPath:innderBorderPath];
    
    CAShapeLayer *visibleRectLayer = [CAShapeLayer layer];
    
    visibleRectLayer.fillRule = kCAFillRuleEvenOdd;
    
    visibleRectLayer.path = outerBorderPath.CGPath;
    
    coverLayer.mask = visibleRectLayer;
}

注意:
1、在构建扫描会还的时候,只有将输出设备添加到会话以后才可以设置输出扫码类型,否则会因为奔溃。
下面是完整代码地址有兴趣的可以看一下,或者直接使用。
2、不要把scanview的创建放在viewdidload方法中,容易出现卡顿,将其创建放在viewdidapear中,在start之前添加一个菊花等待,在start后关闭结束。
https://github.com/tiancanfei/ADQRScanView.git

你可能感兴趣的:(iOS原生扫码(ADQRcodeScanView))