原生二维码扫描

二维码原生扫描
参考博客:
http://www.cnblogs.com/lzjsky/p/5057134.html
http://my.oschina.net/u/2340880/blog/405847
http://www.jianshu.com/p/d24282dd6e72
http://c0ming.me/qr-code-scan/
遇到的bug:

[AVCaptureMetadataOutput setMetadataObjectTypes:] - unsupported type found.  Use -availableMetadataObjectTypes.'

原因:输出格式要在加入session后设置
(http://stackoverflow.com/questions/25480636/avcapturemetadataoutput-setmetadataobjecttypes-unspported-type-found)

Demo

//
//  ErweimaView.m
//  二维码扫描Demo
//
//  Created by 小木 on 16/5/17.
//  Copyright © 2016年 小木. All rights reserved.
//

#import "ErweimaView.h"
@interface ErweimaView()<AVCaptureMetadataOutputObjectsDelegate>
/**
 *  AVCaptureSession 管理输入(AVCaptureInput)和输出(AVCaptureOutput)流,包含开启和停止会话方法。
 */
@property (nonatomic, strong) AVCaptureSession *session;
/**
 *  AVCaptureDeviceInput 是AVCaptureInput的子类,可以作为输入捕获会话,用AVCaptureDevice实例初始化。
 */
@property (nonatomic, strong) AVCaptureDeviceInput *input;
/**
 *  AVCaptureDevice 代表了物理捕获设备如:摄像机。用于配置等底层硬件设置相机的自动对焦模式。
 */
@property (nonatomic, strong) AVCaptureDevice *device;
/**
 *  AVCaptureMetadataOutput 是AVCaptureOutput的子类,处理输出捕获会话。捕获的对象传递给一个委托实现AVCaptureMetadataOutputObjectsDelegate协议。协议方法在指定的派发队列(dispatch queue)上执行。
 */
@property (nonatomic, strong) AVCaptureMetadataOutput *output;
/**
 *  AVCaptureVideoPreviewLayerCALayer的一个子类,显示捕获到的相机输出流。
 */
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *outputLayer;
/**
 *  绿线指示器
 */
@property (nonatomic, strong) UIView *indirectorView;
@end
@implementation ErweimaView
- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        [self.layer addSublayer:self.outputLayer];
        UIView *bgView = [[UIView alloc]initWithFrame:frame];
        bgView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];

        //创建遮罩
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:frame];
        [path appendPath:[[UIBezierPath bezierPathWithRect:CGRectMake(SCREEN_WIDTH*0.5-100, 200, 200, 200)] bezierPathByReversingPath]];
        [self addSubview:bgView];
        CAShapeLayer *bgLayer = [CAShapeLayer layer];
        bgLayer.path = path.CGPath;
        [bgView.layer setMask:bgLayer];

        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(inputPortChange) name:AVCaptureInputPortFormatDescriptionDidChangeNotification object:nil];


    }
    return self;
}
#pragma mark==========Function
- (void)inputPortChange{
    self.output.rectOfInterest = [self.outputLayer metadataOutputRectOfInterestForRect:CGRectMake(SCREEN_WIDTH*0.5-100, 200, 200, 200)];
}
- (BOOL)startScan{
    [self.session startRunning];
    [self beginScanAnimation];
    return YES;
}
- (void)beginScanAnimation{
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(scanAnimation) userInfo:nil repeats:YES];
    [timer fire];
}
- (void)scanAnimation{
    self.indirectorView.frame = CGRectMake(10, 0, 180, 1);
    [UIView animateWithDuration:3 animations:^{
        self.indirectorView.frame = CGRectMake(10, 200, 180, 1);
    }];
}
#pragma mark==========扫描二维码
//创建回话
- (AVCaptureSession *)session{
    if (!_session) {
        _session = [[AVCaptureSession alloc]init];
        //设置高质量采集率
        [_session setSessionPreset:AVCaptureSessionPresetHigh];
        //添加输入流
        [_session addInput:self.input];
        //添加输出流
        [_session addOutput:self.output];
        //设置扫码支持的编码格式(如下设置条形码和二维码兼容)
        [self.output setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
    }
    return _session;
}
//创建输入流
- (AVCaptureDeviceInput *)input{
    if (!_input) {
        _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
    }
    return _input;
}
//创建输入流
- (AVCaptureMetadataOutput *)output{
    if (!_output) {
        _output = [[AVCaptureMetadataOutput alloc]init];
        //设置代理 在主线程里刷新
        [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    }
    return _output;
}
//创建输出对象图层
- (AVCaptureVideoPreviewLayer *)outputLayer{
    if (!_outputLayer) {
        _outputLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.session];
        [_outputLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        _outputLayer.frame = self.bounds;
        _outputLayer.backgroundColor = [UIColor blackColor].CGColor;


        AVCaptureVideoPreviewLayer *boardLayer = [[AVCaptureVideoPreviewLayer alloc]init];
        boardLayer.borderColor = [UIColor greenColor].CGColor;
        boardLayer.backgroundColor = [UIColor clearColor].CGColor;
        boardLayer.borderWidth = 1;
        boardLayer.frame = CGRectMake(SCREEN_WIDTH*0.5-100, 200, 200, 200);
        [_outputLayer addSublayer:boardLayer];

        [boardLayer addSublayer:self.indirectorView.layer];

    }
    return _outputLayer;
}
//创建设备
- (AVCaptureDevice *)device{
    if (!_device) {
        _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    }
    return _device;
}
- (UIView *)indirectorView{
    if (!_indirectorView) {
        _indirectorView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 180, 1)];
        _indirectorView.backgroundColor = [UIColor greenColor];
    }
    return _indirectorView;
}
#pragma mark==========扫描二维码结果回掉
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    if (metadataObjects.count>0) {
        [self.session stopRunning];
        AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
        //输出扫描字符串
        NSLog(@"%@",metadataObject.stringValue);
        if (metadataObject.stringValue.length>0) {
            [self.session stopRunning];
            if ([self.delegate respondsToSelector:@selector(erweimaDidScanWithResult:)]) {
                [self.delegate erweimaDidScanWithResult:metadataObject.stringValue];
            }
        }
    }
}

效果图
这里写图片描述

重点一:扫描范围的设置

        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(inputPortChange) name:AVCaptureInputPortFormatDescriptionDidChangeNotification object:nil];
    }
    return self;
}
#pragma mark==========Function
- (void)inputPortChange{
    self.output.rectOfInterest = [self.outputLayer metadataOutputRectOfInterestForRect:CGRectMake(SCREEN_WIDTH*0.5-100, 200, 200, 200)];
}

重点二:遮罩层的设置
1,遮罩层就是把扫描区域挖空的view

        UIView *bgView = [[UIView alloc]initWithFrame:frame];
        bgView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:frame];
        [path appendPath:[[UIBezierPath bezierPathWithRect:CGRectMake(SCREEN_WIDTH*0.5-100, 200, 200, 200)] bezierPathByReversingPath]];
        [self addSubview:bgView];
        CAShapeLayer *bgLayer = [CAShapeLayer layer];
        bgLayer.path = path.CGPath;
        [bgView.layer setMask:bgLayer];

重点三:扫描区域UI的绘制
这个其实只是装饰效果,不具备任何功能

        //扫描区域绘制
        AVCaptureVideoPreviewLayer *boardLayer = [[AVCaptureVideoPreviewLayer alloc]init];
        boardLayer.borderColor = [UIColor greenColor].CGColor;
        boardLayer.backgroundColor = [UIColor clearColor].CGColor;
        boardLayer.borderWidth = 1;
        boardLayer.frame = CGRectMake(SCREEN_WIDTH*0.5-100, 200, 200, 200);
        [_outputLayer addSublayer:boardLayer];
        [boardLayer addSublayer:self.indirectorView.layer];

    }
    return _outputLayer;
}
- (UIView *)indirectorView{
    if (!_indirectorView) {
        _indirectorView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 180, 1)];
        _indirectorView.backgroundColor = [UIColor greenColor];
    }
    return _indirectorView;
}

原理稀释
扫码是一个从摄像头(input)到 解析出字符串(output) 的过程,用AVCaptureSession 来协调。其中是通过 AVCaptureConnection 来连接各个 input 和 output,还可以用它来控制 input 和 output 的 数据流向
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值