ios开发原生的扫描二维码的实现以及限制扫描区域rectOfInterest遇到的一些坑
早前面试的时候被问到扫描使用的是什么 脱口而出用的Zbar ,然后就问为何不用原生的,效率更高啊,话说刚开始干那时候只求实现,不求效率,也不知怎么的回答。现在回想,最好的回答就是: 需要相册扫描,原生的实现不了啊。
ZBar 优点: 可以实现相册相片扫描 但是效率有点低.
原生的: 效率高,但是不能做相册扫描.
下面放代码
做了些许优化
主要体现在,首次进入扫一扫vc 启动扫一扫的代码放在了
-(void)viewDidAppear:(BOOL)animated ,便于先进入在启动,不会给人卡的感觉.然后进入这个页面设置背景为黑色,当扫一扫启动ok的时候在把 背景设备为白色, 也有的在等待的时间内给他一个等待动画.
ios开发设置rectOfInterest不管用
接下来说的就是扫一扫区域限制的问题
首先属性大家基本都知道
AVCaptureMetadataOutput 的对象的属性 rectOfInterest
output.rectOfInterest=CGRectMake(100/height, (width/2 -110)/width, 220/height, 220/width);//width指的是AVCaptureVideoPreviewLayer 对象的宽度 height指的是AVCaptureVideoPreviewLayer 对象的高度
//CGRectMake(y/deviceHeight, x/deviceWidth, height/deviceHeight, width/deviceWidth);
解释下CGRectMake写法:都把x y width height 互换 了的.你扫一扫的那个框框的 起点坐标为 x y 宽为width 高为height ,deviceHeight ,deviceWidth指的是AVCaptureVideoPreviewLayer对象的高度但是写的时候如上,经过多次测试所得数据.大部分的宽度跟高度是相等的,但是在这里的比例是不相等的, 因为手机宽高不等. 好了接下来直接上代码.解释的不到位的就结合代码看吧.
//.h
#import <UIKit/UIKit.h>
@interface ScanCodeViewController : UIViewController
@property(nonatomic,strong)NSString *frameWhere;
@property(strong,nonatomic)void(^getSysString)(NSString*);
@end
//.m
#import "ScanCodeViewController.h"
#import <AVFoundation/AVFoundation.h>
#define widthMainControl [UIScreen mainScreen].bounds.size.width
#define heightMainControl [UIScreen mainScreen].bounds.size.height
#define colorMainBG [UIColor colorWithRed:253/255.0 green:199/255.0 blue:117/255.0 alpha:1]
@interface ScanCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate>
{
AVCaptureSession * session;//输入输出的中间桥梁
int startY;
int topHeight;
BOOL onceScan;
}
@property (strong, nonatomic) UIImageView *lineImg;
@property(nonatomic,strong)NSTimer *scanLineTimer;
@end
@implementation ScanCodeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"扫一扫";
self.view.backgroundColor = [UIColor blackColor];
onceScan = YES;
int screenHeigth = (int)(heightMainControl);
topHeight = 100;
if (screenHeigth == 480) {
topHeight = 50;
}else if (screenHeigth == 568){
topHeight = 60;
}
}
-(void)makeUI
{
self.view.backgroundColor = [UIColor whiteColor];
UIImageView *kaungImg = [[UIImageView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 -110, topHeight, 220, 220)];
kaungImg.image = [UIImage imageNamed:@"sys-k"];
[self.view addSubview:kaungImg];
self.lineImg = [[UIImageView alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 -100, topHeight + 10, 200, 7)];
self.lineImg.image = [UIImage imageNamed:@"sys-ht"];
[self.view addSubview:self.lineImg];
for (int i=0 ; i< 4; i++) {
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(widthMainControl/2 - 110, 0, widthMainControl/2 - 110, 100)];
if (i == 0) {
leftView.frame = CGRectMake(0, 0, widthMainControl/2 - 110, heightMainControl - 64 + 64);
}else if (i == 1){
leftView.frame = CGRectMake(widthMainControl/2 - 110, 0, 220, topHeight);
}else if (i == 2){
leftView.frame = CGRectMake(widthMainControl/2 - 110 + 220, 0, widthMainControl/2 - 110, heightMainControl - 64 + 64);
}else if (i == 3){
leftView.frame = CGRectMake(widthMainControl/2 - 110, topHeight + 220, 220, heightMainControl - 64 - 220 - topHeight + 64);
}
leftView.backgroundColor = [UIColor blackColor];
leftView.alpha = 0.4;
[self.view addSubview:leftView];
}
//手动输入设备Id的按钮
UIButton *hangBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[hangBtn setTitle:@"取消" forState:UIControlStateNormal];
hangBtn.frame = CGRectMake(self.view.frame.size.width/2 -110, topHeight + 270, 220, 40);
[hangBtn addTarget:self action:@selector(pushToNextVC) forControlEvents:UIControlEventTouchUpInside];
hangBtn.layer.cornerRadius = 5;
[hangBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
hangBtn.layer.masksToBounds = YES;
hangBtn.backgroundColor = colorMainBG;
[self.view addSubview:hangBtn];
[self createTimer];
}
-(void)pushToNextVC
{
[self dismissViewControllerAnimated:YES completion:nil];
// AddDeviceByHandViewController *addDevice = [[AddDeviceByHandViewController alloc] init];
// [self.navigationController pushViewController:addDevice animated:YES];
}
-(void)viewDidAppear:(BOOL)animated
{
[UIView animateWithDuration:0.3 animations:^{
self.view.backgroundColor = [UIColor whiteColor];
}];
//获取摄像设备
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()];
float width = self.view.frame.size.width;// AVCaptureVideoPreviewLayer的对象的宽度
float height = self.view.frame.size.height;// AVCaptureVideoPreviewLayer的对象的高度
output.rectOfInterest=CGRectMake(100/height, (width/2 -110)/width, 220/height, 220/width);
//CGRectMake(y, x, height, width);
//初始化链接对象
session = [[AVCaptureSession alloc]init];
//高质量采集率
[session setSessionPreset:AVCaptureSessionPresetHigh];
[session addInput:input];
[session addOutput:output];
//设置扫码支持的编码格式(如下设置条形码和二维码兼容)
output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
AVCaptureVideoPreviewLayer * layer = [AVCaptureVideoPreviewLayer layerWithSession:session];
layer.videoGravity=AVLayerVideoGravityResizeAspectFill;
layer.frame=self.view.layer.bounds;
[self.view.layer insertSublayer:layer atIndex:0];
//开始捕获
[session startRunning];
[self makeUI];
}
#define LINE_SCAN_TIME 0.01 // 扫描线从上到下扫描所历时间(s)
- (void)createTimer {
startY = 110 ;
self.scanLineTimer =
[NSTimer scheduledTimerWithTimeInterval:LINE_SCAN_TIME
target:self
selector:@selector(moveScanImg)
userInfo:nil
repeats:YES];
}
-(void)moveScanImg
{
int startX = self.view.frame.size.width/2 -100;
startY += 1;
if (startY > topHeight + 210) {
startY = topHeight + 10;
}
self.lineImg.frame = CGRectMake(startX,startY , 200, 7);
}
-(void)viewDidDisappear:(BOOL)animated
{
[self.scanLineTimer invalidate];
}
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
if (metadataObjects.count>0) {
//[session stopRunning];
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex : 0 ];
//输出扫描字符串
NSLog(@"result:%@",metadataObject.stringValue);
[self dismissViewControllerAnimated:YES completion:^{
self.getSysString(metadataObject.stringValue);
}];
}
}
进入这个界面之前的页面获得扫一扫的数据
pushScan.getSysString = ^(NSString *str){
startConnectStr = str;
if (str) {
//str 就是得到的数据
//这里可以在扫一扫之后得到数据做点需要干的
}
};
全文完毕,谢谢查看.