1.导入AVFoundation/AVFoundation.h框架
2.在初始化时 定义imageView 作为自定义的现实区域
3.绘制遮盖层 可视区域之外的部分 半透明的遮盖 默认扫描二维码是整个手机屏幕的
4.配置 device input output session 相关信息
5.设置output的现实区域 这里要注意 坐标原点于默认的相反 x 是以前的y 类似 宽高 并且这里是0-1之间的 比例数字
直接上代码
#import <AVFoundation/AVFoundation.h>
@interface SecondViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property (strong,nonatomic) AVCaptureDevice * device;
@property (strong,nonatomic) AVCaptureDeviceInput * input;
@property (strong,nonatomic) AVCaptureMetadataOutput * output;
@property (strong,nonatomic) AVCaptureSession * session;
@property (strong,nonatomic) AVCaptureVideoPreviewLayer * preview;
@property (nonatomic,strong) UIImageView *animationView;
@property (nonatomic,strong) NSTimer *timer;
@property (nonatomic,strong) UIImageView *imageView;
@property (nonatomic,strong) CALayer *maskLayer;
@property (nonatomic,assign) CMVideoDimensions dimensions;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
//扫描的边框
UIImage *image = [UIImage imageNamed:@"qrcode_border"];
//这里是剪切拉伸一个图片(把四角拉出去 内部内容填充)
UIImage *boundImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(25, 25, 26, 26)];
self.imageView = [[UIImageView alloc] initWithImage:boundImage];
//左边从70px开始
CGFloat width = [UIScreen mainScreen].bounds.size.width - 70 *2;
[self.imageView setFrame:CGRectMake(70, 150, width, width)];
[self.view addSubview:self.imageView];
//框中间动画效果的图片
self.animationView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -width, width, width)];
[self.animationView setImage:[UIImage imageNamed:@"qrcode_scanline_qrcode"]];
[self.imageView addSubview:self.animationView];
self.imageView.clipsToBounds = YES;
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.02f target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
}
-(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)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self begining];
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self endRead:nil];
}
- (void)begining{
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error;
self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
self.output = [[AVCaptureMetadataOutput alloc] init];
self.session = [[AVCaptureSession alloc] init];
//配置session相关联系
if ([_device supportsAVCaptureSessionPreset:AVCaptureSessionPreset1920x1080]) {
_session.sessionPreset = AVCaptureSessionPreset1920x1080;//设置图像输出质量
self.dimensions = (CMVideoDimensions){1080,1920};
}else if ([_device supportsAVCaptureSessionPreset:AVCaptureSessionPreset1280x720]){
_session.sessionPreset = AVCaptureSessionPreset1280x720;
self.dimensions = (CMVideoDimensions){720,1280};
}else if ([_device supportsAVCaptureSessionPreset:AVCaptureSessionPreset640x480]){
_session.sessionPreset = AVCaptureSessionPreset640x480;
self.dimensions = (CMVideoDimensions){480,640};
}else if ([_device supportsAVCaptureSessionPreset:AVCaptureSessionPreset352x288]){
_session.sessionPreset = AVCaptureSessionPreset352x288;
self.dimensions = (CMVideoDimensions){288,352};
}
//这里必须真机 需要相关 相机等等设备 使用时打开这行注释就好
[self.session addInput:self.input];
[self.session addOutput:self.output];
//配置output信息
//设置delegate,输出的类型
[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[self.output setMetadataObjectTypes:self.output.availableMetadataObjectTypes];
// 5. 设置预览图层(用来让用户能够看到扫描情况)
AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
// 5.1 设置preview图层的属性
[preview setVideoGravity:AVLayerVideoGravityResizeAspectFill];
// 5.2 设置preview图层的大小
[preview setFrame:self.view.bounds];
preview.backgroundColor = [UIColor lightGrayColor].CGColor;
// 5.3 将图层添加到视图的图层
[self.view.layer insertSublayer:preview atIndex:0];
self.maskLayer = [[CALayer alloc]init];
self.maskLayer.frame = self.view.layer.bounds;
self.maskLayer.delegate = self;
[self.view.layer insertSublayer:self.maskLayer above:preview];
[self.maskLayer setNeedsDisplay];
/*获取图像输出大小*/
CMVideoDimensions dimensions = self.dimensions;
CGFloat width = dimensions.width;
CGFloat height = dimensions.height;
CGSize size = self.view.bounds.size;
CGFloat p1 = size.height/size.width;
CGFloat p2 = height/width; //与之前设置的图像输出质量应该对应。
CGFloat viewWidth = [UIScreen mainScreen].bounds.size.width - 70 *2;
if (p1 < p2) {
CGFloat fixHeight = self.view.bounds.size.width * height / width; //缩放并剪裁后的高度。
CGFloat fixPadding = (fixHeight - size.height)/2;
_output.rectOfInterest = CGRectMake((150 + fixPadding)/fixHeight,
70/size.width,
viewWidth/fixHeight,
viewWidth/size.width);
} else {
CGFloat fixWidth = self.view.bounds.size.height * width / height;
CGFloat fixPadding = (fixWidth - size.width)/2;
_output.rectOfInterest = CGRectMake(150/size.height,
(70 + fixPadding)/fixWidth,
viewWidth/size.height,
viewWidth/fixWidth);
}
// 6. 启动会话
[self.session startRunning];
[self.timer fire];
}
#pragma mark AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
NSString *stringValue;
if ([metadataObjects count] >0){
//停止扫描
[_session stopRunning];
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
stringValue = metadataObject.stringValue;
if ([metadataObject isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {
//在主线程中刷新UI
[self performSelectorOnMainThread:@selector(endRead:) withObject:stringValue waitUntilDone:YES];
}
}
}
//Note: 蒙板生成。需设置代理,并在退出页面时取消代理。
-(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
UIGraphicsBeginImageContextWithOptions(layer.frame.size, NO, 1.0);
CGContextSetFillColorWithColor(ctx, [UIColor colorWithRed:0 green:0 blue:0 alpha:0.6].CGColor);
CGContextFillRect(ctx, layer.frame);
CGRect scanFrame = [self.view convertRect:self.imageView.frame fromView:self.imageView.superview];
CGContextClearRect(ctx, scanFrame);
}
- (void)endRead:(id)userInfo{
[self.session stopRunning];
[self.timer invalidate];
self.maskLayer.delegate = nil;
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"二维码" message:userInfo preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self.navigationController popViewControllerAnimated:YES];
}]];
[self presentViewController:alertController animated:YES completion:nil];
}
@end