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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,515评论 25 707
  • 尼采的作品,尽是诗歌、怒骂、谜语、誓言、忏悔等杂糅的辞章,你找不到一篇类似康德或者黑格尔那样逻辑严密的文...
    山大一只猫阅读 849评论 1 1
  • 啪叽 (*≧≦) 沉迷于维勇无法自拔(* ̄3 ̄)╭ 接第一季完结后哒,因为第十二集最后的那一幕突发灵感,哎呀~勇利...
    82a55490f90f阅读 1,537评论 0 6
  • 作者:李蚌公众号:李蚌书吧 微信号:lb55077 总是见到一个男人,平头,中年,穿铜锈绿的一件T恤,在路上。我...
    李蚌阅读 587评论 0 50