本帖最后由 Sian 于 2015-12-3 17:55 编辑
1、先上图看看效果
2、设计思路
2.1、利用AVCaptureMetadataOutput固有的输出属性,能够输出二维码及条形码的解析结果
2.2、利用Quartz 2D绘出基本扫描界面,结合动画效果,简单又高效!2.3、只需两个类,一个控制器,一个视图:SAScanCtrl SAScan
2.3、其他内容在代码中给出相关注释说明
3、部分代码
SAScanCtrl.h
[Objective-C] 纯文本查看 复制代码 //
// SAScanCtrl.h
//
//
// Created by 余西安 on 15/12/3.
// Copyright © 2015年 Sian. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef void (^SAScanBlock)(NSString *string);
@interface SAScanCtrl : UIViewController
@property (nonatomic, copy) SAScanBlock block;
- (instancetype)initWithBlock:(SAScanBlock)block;
@end
SAScanCtrl.m[Objective-C] 纯文本查看 复制代码 //
// SAScanCtrl.m
//
//
// Created by 余西安 on 15/12/3.
// Copyright © 2015年 Sian. All rights reserved.
//
#import "SAScanCtrl.h"
#import "SAScan.h"
#import <AVFoundation/AVFoundation.h>
@interface SAScanCtrl ()<AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVAudioPlayer *player;
@property (nonatomic, strong) SAScan *scan;
@end
@implementation SAScanCtrl
- (instancetype)initWithBlock:(SAScanBlock)block
{
if (self = [super init]){
self.block = block;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationItem setTitle:@"扫一扫"];
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 setRectOfInterest:CGRectMake(0.12 , 0.12, 0.8, 0.8)];
//初始化链接对象
self.session = [[AVCaptureSession alloc] init];
[self.session addInput:input];
[self.session addOutput:output];
[self.session setSessionPreset:AVCaptureSessionPresetHigh];
//设置扫码支持的编码格式(如下设置条形码和二维码兼容)
[output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]];
AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
layer.frame = self.view.bounds;
[self.view.layer insertSublayer:layer atIndex:0];
self.scan = [[SAScan alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.scan];
NSURL *url = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"scan" ofType:@"mp3"]];
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"重试" style:UIBarButtonItemStylePlain target:self action:@selector(startRunning)];
[self.navigationItem setRightBarButtonItem:item];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.session startRunning];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.scan startAnimation];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.session stopRunning];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
if (metadataObjects.count > 0){
AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects firstObject];
[self.player play];
[self.scan stopAnimation];
[self.session stopRunning];
if (self.block) self.block(metadataObject.stringValue);
[self.navigationController popViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
- (void)startRunning
{
[self.session startRunning];
[self.scan startAnimation];
}
@end
Scan.h[Objective-C] 纯文本查看 复制代码 //
// SAScan.h
//
//
// Created by 余西安 on 15/12/3.
// Copyright © 2015年 Sian. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface SAScan : UIView
@property (nonatomic, strong) UIImageView *scanLine;
- (void)startAnimation;
- (void)stopAnimation;
@end
Scan.m[Objective-C] 纯文本查看 复制代码 //
// SAScan.m
//
//
// Created by 余西安 on 15/12/3.
// Copyright © 2015年 Sian. All rights reserved.
//
#import "SAScan.h"
@implementation SAScan
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]){
self.backgroundColor = [UIColor clearColor];
UIImage *line = [UIImage imageNamed:@"scanLine.png"];
self.scanLine = [[UIImageView alloc] initWithImage:line];
[self.scanLine setHidden:YES];
[self addSubview:self.scanLine];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
//非扫码区域半透明
{
CGFloat w = self.bounds.size.width * 0.7;
CGFloat x = (self.bounds.size.width - w) * 0.5;
CGFloat y = (self.bounds.size.height - w) * 0.5;
{ // 外围区域填充半透明黑色
// 设置非识别区域颜色
CGContextSetRGBFillColor(context, 0, 0, 0, 0.6);
// 扫码区域上面填充
CGRect rect = CGRectMake(0, 0, self.frame.size.width, y);
CGContextFillRect(context, rect);
// 扫码区域左边填充
rect = CGRectMake(0, y, x, w);
CGContextFillRect(context, rect);
// 扫码区域右边填充
rect = CGRectMake(x + w, y, x, w);
CGContextFillRect(context, rect);
// 扫码区域下面填充
rect = CGRectMake(0, y + w, self.frame.size.width, self.frame.size.height - y - w);
CGContextFillRect(context, rect);
}
{ // 中间可视区域画边框
UIColor *whiteColor = [UIColor colorWithWhite:1.0 alpha:0.5];
CGContextSetStrokeColorWithColor(context, whiteColor.CGColor);
CGContextSetLineWidth(context, 1);
CGContextAddRect(context, CGRectMake(x, y, w, w));
CGContextStrokePath(context);
}
{ // 中间可视区域画角框
CGFloat lineWidth = 4.0f;
CGFloat angleWidth = 15.0f;
UIColor *greenColor = [UIColor colorWithRed:0 green:1.0 blue:0 alpha:0.8];
CGContextSetLineWidth(context, lineWidth);
CGContextSetStrokeColorWithColor(context, greenColor.CGColor);
// 左上角
CGContextMoveToPoint(context, x, y + angleWidth);
CGContextAddLineToPoint(context, x, y);
CGContextAddLineToPoint(context, x + angleWidth, y);
// 右上角
CGContextMoveToPoint(context, x + w - angleWidth, y);
CGContextAddLineToPoint(context, x + w, y);
CGContextAddLineToPoint(context, x + w, y + angleWidth);
// 右下角
CGContextMoveToPoint(context, x + w, y + w - angleWidth);
CGContextAddLineToPoint(context, x + w, y + w);
CGContextAddLineToPoint(context, x + w - angleWidth, y + w);
// 左下角
CGContextMoveToPoint(context, x + angleWidth, y + w);
CGContextAddLineToPoint(context, x, y + w);
CGContextAddLineToPoint(context, x, y + w - angleWidth);
}
CGContextStrokePath(context);
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat width = self.bounds.size.width;
CGFloat y = (self.bounds.size.height - width * 0.7) * 0.5;
self.scanLine.frame = CGRectMake(0, y, width, 12);
}
- (void)startAnimation
{
CGFloat width = self.bounds.size.width;
CGFloat y = (self.bounds.size.height - width * 0.7) * 0.5;
self.scanLine.frame = CGRectMake(0, y, width, 12);
self.scanLine.hidden = NO;
[UIView animateWithDuration:2.5 delay:0 options:UIViewAnimationOptionRepeat | UIViewAnimationOptionCurveLinear animations:^{
self.scanLine.center = CGPointMake(width * 0.5, y + width * 0.7);
} completion:^(BOOL finished) {
if (finished) self.scanLine.center = CGPointMake(width * 0.5, y);
}];
}
- (void)stopAnimation
{
self.scanLine.hidden = YES;
[self.scanLine.layer removeAllAnimations];
}
@end
4、使用只需一行代码:
SAScanCtrl *scan = [[SAScanCtrl alloc] initWithBlock:^(NSString *string) { [[[UIAlertView alloc] initWithTitle:nil message:string delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show]; }]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:scan]; [self presentViewController:nav animated:YES completion:nil];
5、Demo下载
|