先说扫描的 ios7&later
引入类库
#import
签协议
@interface NAHomeBarcodeViewController ()
声明属性
@property (nonatomic, strong) AVCaptureSession *session;//输入输出的中间桥梁
@property (strong,nonatomic)AVCaptureDevice *device;
@property (strong,nonatomic)AVCaptureDeviceInput *input;
@property (strong,nonatomic)AVCaptureMetadataOutput *output;
@property (strong,nonatomic)AVCaptureVideoPreviewLayer * previewLayer;
@property (nonatomic, strong) CADisplayLink *link;//定时器
@property (nonatomic, strong) CALayer *scanLayer;//扫描线
@property (nonatomic, strong) UIView *boxView;//扫描框
@property (nonatomic, strong) NSString *strOfResult;//保存二维码结果
//在扫描框上下左右的灰色透明遮罩
@property (nonatomic, strong) UIView *topV;
@property (nonatomic, strong) UIView *leftV;
@property (nonatomic, strong) UIView *rightV;
@property (nonatomic, strong) UIView *bottomV;
添加定时器, 让扫描线上下滚动
#pragma mark - 创建定时器
- (void)createTimer{
_link = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateFrame)];
_link.frameInterval = 1.5;
[_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
#pragma mark - 上下刷
- (void)updateFrame{
CGRect frame = self.scanLayer.frame;
if (self.scanLayer.frame.origin.y > self.boxView.frame.size.height) {
frame.origin.y = -50;
self.scanLayer.frame = frame;
}else{
frame.origin.y += 1;
self.scanLayer.frame = frame;
}
}
然后就是添加扫描相关事项了
#pragma mark - 扫描
- (void)scanCode{
//1.获取输入设备
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
//创建输入对象
NSError *error;
_input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];
if (!_input) {
[self alertNotOpenCamera];
}
//3.创建输出对象
_output = [[AVCaptureMetadataOutput alloc] init];
//4.设置代理监听输出对象的输出流 说明: 使用主线程队列, 相应比较同步, 使用其他队列, 相应不同步, 容易让用户产生不好的体验
[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
//5.创建会话
_session = [[AVCaptureSession alloc] init];
//高质量采集率
[self.session setSessionPreset:AVCaptureSessionPresetHigh];
//6.将输入输出对象添加到会话
[self.session addInput:_input];
[self.session addOutput:self.output];
//7.告诉输出对象, 需要输出什么样的数据 提示: 一定要先设置会话的输出为output之后, 再指定输出的源数据类型!
//设置扫码支持的编码格式(如下设置条形码和二维码兼容)
[self.output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]];
//8. 创建预览图层
_previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
_previewLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:_previewLayer atIndex:0];
//9.设置扫描范围
// self.output.rectOfInterest = CGRectMake(0.2, 0.18, 0.6, 0.5);
CGSize size = self.view.bounds.size;
CGRect cropRect = CGRectMake(0.2 * SCREEN_WIDTH, 0.18 * SCREEN_HEIGHT, 0.6 * SCREEN_WIDTH, 0.5 * SCREEN_HEIGHT);
CGFloat p1 = size.height/size.width;
CGFloat p2 = 1920./1080.; //使用了1080p的图像输出
if (p1 < p2) {
CGFloat fixHeight = self.view.bounds.size.width * 1920. / 1080.;
CGFloat fixPadding = (fixHeight - size.height)/2;
self.output.rectOfInterest = CGRectMake((cropRect.origin.y + fixPadding)/fixHeight,
cropRect.origin.x/size.width,
cropRect.size.height/fixHeight,
cropRect.size.width/size.width);
} else {
CGFloat fixWidth = self.view.bounds.size.height * 1080. / 1920.;
CGFloat fixPadding = (fixWidth - size.width)/2;
self.output.rectOfInterest = CGRectMake(cropRect.origin.y/size.height,
(cropRect.origin.x + fixPadding)/fixWidth,
cropRect.size.height/size.height,
cropRect.size.width/fixWidth);
}
//10.设置扫描框
[self.view addSubview:self.boxView];
//设置扫描线
[self.boxView.layer addSublayer:self.scanLayer];
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
NSLog(@"允许扫描");
//开始扫描
[self.session startRunning];
}else{
NSLog(@"不允许");
return ;
}
}];
//判断是否授权相机
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status == AVAuthorizationStatusDenied) {
[self alertNotOpenCamera];
}
}
创建定时器和创建扫描都是视图即将出现的时候调用的
以下是几个懒加载, 扫描框还是写好大小然后和设计师要张图比较漂亮些
- (CALayer *)scanLayer{
if (!_scanLayer) {
_scanLayer = [[CALayer alloc] init];
_scanLayer.frame = CGRectMake(0, 0, self.boxView.bounds.size.width, 1);
_scanLayer.backgroundColor = [UIColor blueColor].CGColor;
// [self.boxView.layer addSublayer:_scanLayer];
}
return _scanLayer;
}
//扫描框
- (UIView *)boxView{
if (!_boxView) {
_boxView = [[UIView alloc] initWithFrame:CGRectMake(0.2 * SCREEN_WIDTH, 0.18 * SCREEN_HEIGHT, 0.6 * SCREEN_WIDTH, 0.5 * SCREEN_HEIGHT)];
_boxView = [[UIImageView alloc] initWithFrame:CGRectMake(0.15 * SCREEN_WIDTH, 0.18 * SCREEN_HEIGHT, 0.7 * SCREEN_WIDTH, 0.7 * SCREEN_WIDTH)];
[_boxView setImage:[UIImage imageNamed:@"box"]];
// _boxView.layer.borderColor = [UIColor colorWithRed:239 / 255.f green:239 / 255.f blue:239 / 255.f alpha:1.f].CGColor;
// _boxView.layer.borderColor = kRGBColor(38, 64, 255).CGColor;
// _boxView.layer.borderWidth = 0.5;
[self createGrayBackView];
// [self.view addSubview:_boxView];
}
return _boxView;
}
- (void)createGrayBackView{
CGRect topVFrame = CGRectMake(0, 0, SCREEN_WIDTH, 0.18 * SCREEN_HEIGHT);
CGRect leftVFrame = CGRectMake(0, topVFrame.origin.y + topVFrame.size.height, 0.15 * SCREEN_WIDTH, 0.7 * SCREEN_WIDTH);
CGRect bottomVFrame = CGRectMake(0, leftVFrame.origin.y +leftVFrame.size.height, SCREEN_WIDTH, SCREEN_HEIGHT - leftVFrame.origin.y - leftVFrame.size.height);
CGRect rightVFrame = CGRectMake(0.15 * SCREEN_WIDTH + 0.7 * SCREEN_WIDTH, leftVFrame.origin.y, leftVFrame.size.width, leftVFrame.size.height);
self.topV = [[UIView alloc] initWithFrame:topVFrame];
[self.topV setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]];
self.leftV = [[UIView alloc] initWithFrame:leftVFrame];
[self.leftV setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]];
self.bottomV = [[UIView alloc] initWithFrame:bottomVFrame];
[self.bottomV setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]];
self.rightV = [[UIView alloc] initWithFrame:rightVFrame];
[self.rightV setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]];
[self.view addSubview:self.topV];
[self.view addSubview:self.leftV];
[self.view addSubview:self.bottomV];
[self.view addSubview:self.rightV];
}
本VC的生命周期做的几件事
#pragma mark - 视图即将出现
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self createTimer];
[self scanCode];
}
#pragma mark - 视图已经消失
- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
// 记得释放CADisplayLink对象
if(_link != nil){
[_link invalidate];
_link = nil;
}
//回来相机才不会卡住
[_previewLayer removeFromSuperlayer];
}
以下是从相册识别二维码, ios8&later
主要是CIDetector
感谢http://ios.jobbole.com/84730/
首先, 签俩代理
@interface NAScanViewController ()< UIImagePickerControllerDelegate, UINavigationControllerDelegate>
写个属性
@property (nonatomic, strong) UIImagePickerController *imagePicker;
在按钮响应事件里呼出相册, 代理置空这种事就不说了, 自己自觉
#pragma mark - navi右按钮响应事件
- (void)goToAlbum:(UIBarButtonItem *)btn{
//调用相册
self.imagePicker = [[UIImagePickerController alloc]init];
self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
self.imagePicker.delegate = self;
//模态推出照相机页面的样式
self.imagePicker.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
self.imagePicker.allowsEditing = NO;
[self presentViewController:self.imagePicker animated:YES completion:nil];
}
imagePicker的代理回调
#pragma mark - 从相册选完图片的回调
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
NSString *content = [NSString string];
//取出选中的图片
UIImage *pickImage = info[UIImagePickerControllerOriginalImage];
NSData *imageData = [NSData data];
if(UIImagePNGRepresentation(pickImage)){
imageData = UIImagePNGRepresentation(pickImage);
}else if (UIImageJPEGRepresentation(pickImage, 1)){
imageData = UIImageJPEGRepresentation(pickImage, 1);
}
CIImage *ciImage = [CIImage imageWithData:imageData];
//创建探测器
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
NSArray *feature = [detector featuresInImage:ciImage];
//取出探测到的数据
for (CIQRCodeFeature *result in feature) {
content = result.messageString;
}
[picker dismissViewControllerAnimated:YES completion:nil];
if(!kStringIsEmpty(content)){
[self jumpToWebviewWithUrl:content];
}
}
跳转出去时给webView传识别的内容, 一般是url, 然后扫描界面停止扫描, 移除CADisplayLink对象
pragma mark 识别成功的相关操作
- (void)jumpToWebviewWithUrl:(NSString *)url{
self.webViewVc.strOfUrl = url;
//停止扫描
[self.session stopRunning];
//移除CADisplayLink对象
[_link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
_link = nil;
[self.navigationController pushViewController:self.webViewVc animated:YES];
}