项目需求要是用到二维码扫描,这次使用的是AVFoundation框架实现。相对于ZBar和ZXing效率更高(其次这两个库貌似也没有人维护了)、而且现在好多app也只都支持iOS7.0及以上系统。
Demo地址:
github地址
效果图
好了现在就来说说怎么实现吧
1.定义一个类QRCodeReaderView类
#import
@protocol QRCodeReaderViewDelegate
- (void)readerScanResult:(NSString *)result;
@end
@interface QRCodeReaderView : UIView
@property (nonatomic, weak)id delegate;
@property (nonatomic,copy)UIImageView * readLineView;
@property (nonatomic,assign)BOOL is_Anmotion;
@property (nonatomic,assign)BOOL is_AnmotionFinished;
//开启关闭扫描
- (void)start;
- (void)stop;
- (void)loopDrawLine;//初始化扫描线
@end
2.看看.m的实现
#import "QRCodeReaderView.h"
#import
#define DeviceMaxHeight ([UIScreen mainScreen].bounds.size.height)
#define DeviceMaxWidth ([UIScreen mainScreen].bounds.size.width)
#define widthRate DeviceMaxWidth/320
#define contentTitleColorStr @"666666" //正文颜色较深
@interface QRCodeReaderView ()
{
//采集流
AVCaptureSession * session;
NSTimer * countTime;
}
@property (nonatomic, strong) CAShapeLayer *overlay;
@end
@implementation QRCodeReaderView
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
//初始化
[self instanceDevice];
}
return self;
}
初始化并创建
- (void)instanceDevice
{
//扫描区域
UIImage *hbImage=[UIImage imageNamed:@"scanscanBg"];
UIImageView * scanZomeBack=[[UIImageView alloc] init];
scanZomeBack.backgroundColor = [UIColor clearColor];
scanZomeBack.layer.borderColor = [UIColor whiteColor].CGColor;
scanZomeBack.layer.borderWidth = 2.5;
scanZomeBack.image = hbImage;
//添加一个背景图片
CGRect mImagerect = CGRectMake(60*widthRate, (DeviceMaxHeight-200*widthRate)/2, 200*widthRate, 200*widthRate);
[scanZomeBack setFrame:mImagerect];
CGRect scanCrop=[self getScanCrop:mImagerect readerViewBounds:self.frame];
[self addSubview:scanZomeBack];
//获取摄像设备
AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//创建输入流
AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
//创建输出流
AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
//设置代理 在主线程里刷新
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
output.rectOfInterest = scanCrop;
//初始化链接对象
session = [[AVCaptureSession alloc]init];
//高质量采集率
[session setSessionPreset:AVCaptureSessionPresetHigh];
if (input) {
[session addInput:input];
}
if (output) {
[session addOutput:output];
//设置扫码支持的编码格式(如下设置条形码和二维码兼容)
NSMutableArray *a = [[NSMutableArray alloc] init];
if ([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeQRCode]) {
[a addObject:AVMetadataObjectTypeQRCode];
}
if ([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN13Code]) {
[a addObject:AVMetadataObjectTypeEAN13Code];
}
if ([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeEAN8Code]) {
[a addObject:AVMetadataObjectTypeEAN8Code];
}
if ([output.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeCode128Code]) {
[a addObject:AVMetadataObjectTypeCode128Code];
}
output.metadataObjectTypes=a;
}
AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:session];
layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
layer.frame=self.layer.bounds;
[self.layer insertSublayer:layer atIndex:0];
[self setOverlayPickerView:self];
//开始捕获
[session startRunning];
}
扫描线条
-(void)loopDrawLine
{
_is_AnmotionFinished = NO;
CGRect rect = CGRectMake(60*widthRate, (DeviceMaxHeight-200*widthRate)/2, 200*widthRate, 2);
if (_readLineView) {
_readLineView.alpha = 1;
_readLineView.frame = rect;
}
else{
_readLineView = [[UIImageView alloc] initWithFrame:rect];
[_readLineView setImage:[UIImage imageNamed:@"scanLine"]];
[self addSubview:_readLineView];
}
[UIView animateWithDuration:1.5 animations:^{
//修改fream的代码写在这里
_readLineView.frame =CGRectMake(60*widthRate, (DeviceMaxHeight-200*widthRate)/2+200*widthRate-5, 200*widthRate, 2);
} completion:^(BOOL finished) {
if (!_is_Anmotion) {
[self loopDrawLine];
}
_is_AnmotionFinished = YES;
}];
}
- (void)setOverlayPickerView:(QRCodeReaderView *)reader
{
CGFloat wid = 60*widthRate;
CGFloat heih = (DeviceMaxHeight-200*widthRate)/2;
//最上部view
CGFloat alpha = 0.6;
UIView* upView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, DeviceMaxWidth, heih)];
upView.alpha = alpha;
upView.backgroundColor = [self colorFromHexRGB:contentTitleColorStr];
[reader addSubview:upView];
//用于说明的label
UILabel * labIntroudction= [[UILabel alloc] init];
labIntroudction.backgroundColor = [UIColor clearColor];
labIntroudction.frame=CGRectMake(0, 64+(heih-64-50*widthRate)/2, DeviceMaxWidth, 50*widthRate);
labIntroudction.textAlignment = NSTextAlignmentCenter;
labIntroudction.textColor=[UIColor whiteColor];
labIntroudction.text=@"将二维码放入框中,即自动扫描";
[upView addSubview:labIntroudction];
//左侧的view
UIView * cLeftView = [[UIView alloc] initWithFrame:CGRectMake(0, heih, wid, 200*widthRate)];
cLeftView.alpha = alpha;
cLeftView.backgroundColor = [self colorFromHexRGB:contentTitleColorStr];
[reader addSubview:cLeftView];
//右侧的view
UIView *rightView = [[UIView alloc] initWithFrame:CGRectMake(DeviceMaxWidth-wid, heih, wid, 200*widthRate)];
rightView.alpha = alpha;
rightView.backgroundColor = [self colorFromHexRGB:contentTitleColorStr];
[reader addSubview:rightView];
//底部view
UIView * downView = [[UIView alloc] initWithFrame:CGRectMake(0, heih+200*widthRate, DeviceMaxWidth, DeviceMaxHeight - heih-200*widthRate)];
downView.alpha = alpha;
downView.backgroundColor = [self colorFromHexRGB:contentTitleColorStr];
[reader addSubview:downView];
- (void)turnBtnEvent:(UIButton *)button_
{
button_.selected = !button_.selected;
if (button_.selected) {
[self turnTorchOn:YES];
}
else{
[self turnTorchOn:NO];
}
}
扫描区域
-(CGRect)getScanCrop:(CGRect)rect readerViewBounds: (CGRect)readerViewBounds
{
CGFloat x,y,width,height;
x = (CGRectGetHeight(readerViewBounds)-CGRectGetHeight(rect))/2/CGRectGetHeight(readerViewBounds);
y = (CGRectGetWidth(readerViewBounds)-CGRectGetWidth(rect))/2/CGRectGetWidth(readerViewBounds);
width = CGRectGetHeight(rect)/CGRectGetHeight(readerViewBounds);
height = CGRectGetWidth(rect)/CGRectGetWidth(readerViewBounds);
return CGRectMake(x, y, width, height);
}
开始扫描
- (void)start
{
[session startRunning];
}
停止扫描
- (void)stop
{
[session stopRunning];
}
扫描结果
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
if (metadataObjects && metadataObjects.count>0) {
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex : 0 ];
//输出扫描字符串
if (_delegate && [_delegate respondsToSelector:@selector(readerScanResult:)]) {
[_delegate readerScanResult:metadataObject.stringValue];
}
}