將要用到的知識(shí)點(diǎn):AVFoundation 框架策菜,CAGradientLayer ,CAShapeLayer,UIBezierPath;
效果圖
1.聲明(建立一個(gè)ScanCode : UIView類)
.m文件
#import "ScanCode.h"
#import <AVFoundation/AVFoundation.h>
#define SelfW self.bounds.size.width
#define SelfH self.bounds.size.height
#define ScanLineH 30
@interface ScanCode ()<AVCaptureMetadataOutputObjectsDelegate> // 用于處理采集信息的代理
{
AVCaptureSession *session; // 輸入輸出的中間橋梁
CAGradientLayer *scanLayer;
UIView *scanBox;
}
@end
2.實(shí)現(xiàn)代碼
@implementation ScanCode
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
// 獲取攝像設(shè)備
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// 創(chuàng)建輸入流
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
// 創(chuàng)建輸出流
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init];
// 設(shè)置代理垃喊,在主線程里刷新
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 初始化鏈接對(duì)象
session = [[AVCaptureSession alloc]init];
// 高質(zhì)量采集率
[session setSessionPreset:AVCaptureSessionPresetHigh];
[session addInput:input];
[session addOutput:output];
// 設(shè)置掃碼支持的編碼格式(如下設(shè)置條形碼和二維碼兼容)
output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode128Code];
// 實(shí)例化預(yù)覽圖層
AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:session];
// 設(shè)置預(yù)覽圖層填充方式
layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
layer.frame = self.layer.bounds;
[self.layer insertSublayer:layer atIndex:0];
UIView *maskView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SelfW,SelfH)];
[maskView setBackgroundColor:[UIColor colorWithWhite:0 alpha:0.7]];
[self addSubview:maskView];
// 運(yùn)用貝塞爾曲線配合CAShapeLayer
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, SelfW, SelfH)];
// MARK: circlePath 畫(huà)圓
// [path appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(SelfW / 2, 200) radius:100 startAngle:0 endAngle:2*M_PI clockwise:NO]];
// MARK: roundRectanglePath 畫(huà)矩形!
[path appendPath:[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(SelfW *0.2f, SelfH*0.35f, SelfW - SelfW*0.4f, SelfH - SelfH *0.7f) cornerRadius:0] bezierPathByReversingPath]];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = path.CGPath;
[maskView.layer setMask:shapeLayer];
//[self setBackgroundColor:[UIColor colorWithWhite:0 alpha:0.7]];
// 設(shè)置掃描范圍
// 注意袜炕,這個(gè)屬性各個(gè)方向的取值范圍為0-1本谜,表示占layer層的長(zhǎng)度比例,x對(duì)應(yīng)的是距離左上角的垂直距離偎窘,y對(duì)應(yīng)的是距離左上角的水平距離乌助,w對(duì)應(yīng)的是底部距離左上角的垂直距離溜在,h對(duì)應(yīng)的是最右邊距離左上角的水平距離
output.rectOfInterest = CGRectMake(0.35f, 0.2f, 0.7f, 0.8f);
// 設(shè)置掃描框
scanBox = [[UIView alloc]initWithFrame:CGRectMake(SelfW *0.2f, SelfH*0.35f, SelfW - SelfW*0.4f, SelfH - SelfH *0.7f)];
scanBox.layer.borderColor = [UIColor greenColor].CGColor;
scanBox.layer.borderWidth = 1.0f;
[self addSubview:scanBox];
// 掃描線
scanLayer = [[CAGradientLayer alloc]init];
scanLayer.frame = CGRectMake(0, 0, scanBox.bounds.size.width, ScanLineH);
[scanBox.layer addSublayer:scanLayer];
// 設(shè)置漸變顏色方向
scanLayer.startPoint = CGPointMake(0, 0);
scanLayer.endPoint = CGPointMake(0, 1);
// 設(shè)定顏色組
scanLayer.colors = @[(__bridge id)[UIColor clearColor].CGColor,(__bridge id)[UIColor brownColor].CGColor];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(moveScanLayer:) userInfo:nil repeats:YES];
[timer fire];
// 開(kāi)始捕獲
[session startRunning];
}
return self;
}
// 以上之后我們的UI上已經(jīng)可以看到攝像頭捕獲的內(nèi)容,只要實(shí)現(xiàn)代理中的方法他托,就可以完成二維碼條形碼的掃描:
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
if (metadataObjects.count>0) {
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex : 0 ];
[session stopRunning];
//輸出掃描字符串
NSLog(@"%@",metadataObject.stringValue);
[scanLayer removeFromSuperlayer];
}
}
// 實(shí)現(xiàn)計(jì)時(shí)器方法moveScanLayer:
- (void)moveScanLayer:(NSTimer *)timer
{
CGRect frame = scanLayer.frame;
if (scanBox.frame.size.height < (scanLayer.frame.origin.y+ScanLineH + 5)) {
frame.origin.y = -5;
scanLayer.frame = frame;
}else{
frame.origin.y += 5;
[UIView animateWithDuration:0.1 animations:^{
scanLayer.frame = frame;
}];
}
}