二维码扫描

二维码扫描的实现

#import "QRCodeViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "Common.h"

@interface QRCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate>

@property (nonatomic, strong)AVCaptureDevice *device;//设备
@property (nonatomic, strong)AVCaptureInput *input;//输入端
@property (nonatomic, strong)AVCaptureMetadataOutput *output;//输出端
@property (nonatomic, strong)AVCaptureSession *session;//会话
@property (weak, nonatomic) IBOutlet UIView *preView;//显示预览layer
@property (nonatomic, weak)UIImageView *animationView;

@property (nonatomic, strong)NSTimer *animationTimer;

@end

@implementation QRCodeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //配置UI效果
    
    //添加扫描的边框
    UIImage *image = [UIImage imageNamed:@"qrcode_border"];
    UIImage *boundImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(25, 25, 26, 26)];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:boundImage];
    //左边从70px开始
    
    CGFloat width = kScreenWidth - 70 *2;
    [imageView setFrame:CGRectMake(70, 170, width, width)];
    [self.view addSubview:imageView];
    
    
//    添加上动画的图片
    UIImageView *animationView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -width, width, width)];
    [animationView setImage:[UIImage imageNamed:@"qrcode_scanline_qrcode"]];
    //添加到方块视图上
    [imageView addSubview:animationView];
    //超出父视图区域不显示
    imageView.clipsToBounds = YES;
    self.animationView = animationView;
    
    self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:.02f target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
    
    UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancel)];
    self.navigationItem.leftBarButtonItem = leftButton;
    
}

-(void)cancel{
    [self stopRead];
    [self.navigationController popViewControllerAnimated:YES];
}

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
    //开始二维码扫描
    [self reading];
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    //停止二维码扫描
    [self stopRead];
}


-(void)changeImage:(NSTimer *)timer{

    //更新图片产生动画
    self.animationView.frame = CGRectOffset(self.animationView.frame, 0, 2);
    
    if (self.animationView.frame.origin.y >= self.animationView.superview.frame.size.height) {
        self.animationView.frame = CGRectMake(0, -CGRectGetHeight(self.animationView.superview.frame), self.animationView.frame.size.width, self.animationView.frame.size.height);
    }
}

//二维码扫描
-(void)reading{
    //1.构造device  获得扫描设备:(摄像头)
    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    //2.构造input   生成连接设备和session的input
    NSError *error;
    self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
    
    //3.构造output,元数据
    self.output = [[AVCaptureMetadataOutput alloc] init];
    //4.session
    self.session = [[AVCaptureSession alloc] init];
    [self.session addInput:self.input];
    [self.session addOutput:self.output];
 
//5.配置output
    //设置delegate,输出的类型    一定要将output添加到session中后,再设置
    dispatch_queue_t queue = dispatch_queue_create("queue", NULL);
    [self.output setMetadataObjectsDelegate:self queue:queue];
    [self.output setMetadataObjectTypes:self.output.availableMetadataObjectTypes];
    
    //6.添加预览功能  可以预览device捕捉到的画面
    AVCaptureVideoPreviewLayer *layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
    [layer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [layer setFrame:self.view.bounds];
    [self.preView.layer addSublayer:layer];
    
    
    //生成一个图片,周围半透明,中间不透明,作为layer的mask层
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [[UIScreen mainScreen] scale]);
    CGContextRef context = UIGraphicsGetCurrentContext();
    //绘制底层的半透明效果
    CGContextSetRGBFillColor(context, 0, 0, 0, 0.9f);
    CGContextAddRect(context, self.view.bounds);
    CGContextFillPath(context);
    
    //绘制中间的不透明区域
    CGContextSetRGBFillColor(context, 1, 1, 1, 1.f);
    //中间方块区域
    CGContextAddRect(context, self.animationView.superview.frame);
    CGContextFillPath(context);
    
    //生成图片
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    //释放资源
    UIGraphicsEndImageContext();
    
    CALayer *maskLayer= [[CALayer alloc] init];
    maskLayer.bounds = self.preView.bounds;
    maskLayer.position = self.preView.center;
    maskLayer.contents = (__bridge id)(image.CGImage);
    layer.mask = maskLayer;
    layer.masksToBounds = YES;
    
    //7.启动服务
    [self.session startRunning];
    [self.animationTimer fire];
}
//停止二维码扫描
-(void)stopRead{
    [self.session stopRunning];
    //停止一个timer
    [self.animationTimer invalidate];
}


//代理服务,注意该方法的调用是在穿行队列中 -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{ //接收元数据 if (metadataObjects.count != 0) { AVMetadataMachineReadableCodeObject *codeObj = metadataObjects[0]; if ([codeObj isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) { NSLog(@"%@", [codeObj stringValue]); //在主线程中刷新UI [self performSelectorOnMainThread:@selector(cancel) withObject:nil waitUntilDone:YES]; } } }
原文地址:https://www.cnblogs.com/10-19-92/p/4955776.html