五一之前 公司安排做個小項目。主要功能就是掃一掃,比較簡單 分享給大家。
.h里面
#import <UIKit/UIKit.h>
@protocol JYScanViewDelegate <NSObject>
-(void)getScanDataString:(NSString*)scanDataString;
@end
@interface JYScanView : UIView
@property (nonatomic,assign) id<JYScanViewDelegate> delegate;
@property (nonatomic,assign) int scanW; //掃描框的寬
- (void)startRunning; //開始掃描
- (void)stopRunning; //停止掃描
@end
.m里面
#import "JYScanView.h"
#import <AVFoundation/AVFoundation.h>
@interface JYScanView ()<AVCaptureMetadataOutputObjectsDelegate>
{
AVCaptureSession * session;//輸入輸出的中間橋梁
int line_tag;
UIView *highlightView;
NSString *scanMessage;
BOOL isRequesting;
}
@property (nonatomic,weak) UIView *leftView;
@property (nonatomic,weak) UIView *rightView;
@property (nonatomic,weak) UIView *upView;
@property (nonatomic,weak) UIView *downView;
@property (nonatomic,weak) UIImageView *centerView; //掃描框
@property (nonatomic,weak) UIImageView *line; //掃描線
@property (nonatomic,weak) UIButton *lightBtn;//手電筒
@end
@implementation JYScanView
@synthesize delegate;
- (instancetype)init{
if (self = [super init]) {
[self setUp];
}
return self;
}
/**
* 不管調用的init還是initWithFrame,都會來到這里
*/
- (instancetype)initWithFrame:(CGRect)frame{
if (self =[super initWithFrame:frame]) {
[self setUp];
}
return self;
}
/**
* 初始化
*/
- (void)setUp{
[self instanceDevice];
}
/**
* 設置掃碼框的寬
*/
-(void)setScanW:(int)scanW{
_scanW = scanW;
[self layoutSubviews];
}
/**
* 配置相機屬性
*/
- (void)instanceDevice{
line_tag = 10000 + 1116;
AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
AVCaptureMetadataOutput * output = [[AVCaptureMetadataOutput alloc]init];
//這個地方比較重要 因為沒有寫這個的話 掃描的范圍是全屏范圍 也就是說有可能你在屏幕顯示的左上角 或者右下角任意一個位置都能掃到二維碼
//但是這樣的用戶體驗效果就不好了 再說了 咱們是讓用戶在掃描框內進行掃描的 這里就是為了解決這個問題 設置掃描范圍
//這里要記住rectOfInterest這個方法設置的區域是相對于設備的大小的,默認值是CGRectMake(0, 0, 1, 1),是有比例關系的
[output setRectOfInterest:CGRectMake((WidthScale(70))/SCREEN_HEIGHT,((ScreenWidth-220)/2)/ScreenWidth,240/ScreenWidth,240/ScreenWidth)];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
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];
[session addObserver:self forKeyPath:@"running" options:NSKeyValueObservingOptionNew context:nil];
[session startRunning];
}
/**
* 監聽掃碼狀態-修改掃描動畫
*/
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{
if ([object isKindOfClass:[AVCaptureSession class]]) {
BOOL isRunning = ((AVCaptureSession *)object).isRunning;
if (isRunning) {
[self addAnimation];
}else{
[self removeAnimation];
}
}
}
/**
* 獲取掃碼結果
*/
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
if (metadataObjects.count>0) {
[self stopRunning];
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex :0];
//輸出掃描字符串
NSString *data = metadataObject.stringValue;
if (data) {
NSLog(@"%@",data);
scanMessage = data;
if(delegate && [delegate respondsToSelector:@selector(getScanDataString:)])
{
[delegate getScanDataString:scanMessage];
}
NSLog(@"%@",scanMessage);
}
}
}
/**
* 創建掃碼頁面
*/
- (void)setOverlayPickerView
{
//左側的view 原來寬30
UIView *leftView = [[UIView alloc]init];
leftView.alpha = 0.5;
leftView.backgroundColor = [UIColor blackColor];
[self addSubview:leftView];
_leftView = leftView;
//右側的view
UIView *rightView = [[UIView alloc]init];
rightView.alpha = 0.5;
rightView.backgroundColor = [UIColor blackColor];
[self addSubview:rightView];
_rightView = rightView;
//最上部view
UIView *upView = [[UIView alloc]init];
upView.alpha = 0.5;
upView.backgroundColor = [UIColor blackColor];
[self addSubview:upView];
_upView = upView;
//底部view
UIView *downView = [[UIView alloc]init];
downView.alpha = 0.5;
downView.backgroundColor = [UIColor blackColor];
[self addSubview:downView];
_downView = downView;
UIImageView *centerView = [[UIImageView alloc]init];
//掃描框圖片的拉伸,拉伸中間一塊區域
UIImage *scanImage = [UIImage imageNamed:@"QR"];
CGFloat top = 34*0.5-1; // 頂端蓋高度
CGFloat bottom = top ; // 底端蓋高度
CGFloat left = 34*0.5-1; // 左端蓋寬度
CGFloat right = left; // 右端蓋寬度
UIEdgeInsets insets = UIEdgeInsetsMake(top, left, bottom, right);
scanImage = [scanImage resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch];
centerView.image = scanImage;
centerView.contentMode = UIViewContentModeScaleAspectFit;
centerView.backgroundColor = [UIColor clearColor];
[self addSubview:centerView];
_centerView = centerView;
//掃描線
UIImageView *line = [[UIImageView alloc]init];
line.tag = line_tag;
line.image = [UIImage imageNamed:@"scanline"];
line.contentMode = UIViewContentModeScaleAspectFill;
line.backgroundColor = [UIColor clearColor];
line.clipsToBounds = YES;
[self addSubview:line];
_line = line;
//手電筒
UIButton *lightBtn = [[UIButton alloc]init];
[lightBtn setImage:[UIImage imageNamed:@"燈"] forState:UIControlStateNormal];
[lightBtn addTarget:self action:@selector(clickLightBtn:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:lightBtn];
_lightBtn = lightBtn;
[self layoutSubviews];
}
- (void)layoutSubviews{
[super layoutSubviews];
if(self.scanW){
}else{
self.scanW = 250;
}
//掃描框的寬
CGFloat scanViewW = self.scanW;
//左側的view 原來寬30
_leftView.frame = CGRectMake(0, 0, (ScreenWidth - scanViewW) * 0.5, self.frame.size.height);
//右側的view
_rightView.frame = CGRectMake(self.frame.size.width-((ScreenWidth - scanViewW) * 0.5), 0, (ScreenWidth - scanViewW) * 0.5, self.frame.size.height);
//最上部view
_upView.frame = CGRectMake((ScreenWidth - scanViewW) * 0.5, 0, scanViewW, 150);
//底部view
_downView.frame = CGRectMake((ScreenWidth - scanViewW) * 0.5, CGRectGetMaxY(_upView.frame) + scanViewW, scanViewW, ScreenHeight - (CGRectGetMaxY(_upView.frame) + scanViewW));
//掃碼框
_centerView.frame = CGRectMake(CGRectGetMaxX(_leftView.frame), CGRectGetMaxY(_upView.frame), scanViewW, scanViewW);
//掃描線
_line.frame = CGRectMake((ScreenWidth - scanViewW) * 0.5, CGRectGetMaxY(_upView.frame), scanViewW, 2);
//手電筒
_lightBtn.frame = CGRectMake(ScreenWidth/2 -20, ScreenHeight - 180, 40, 40);
}
/**
* 添加掃碼動畫
*/
- (void)addAnimation{
UIView *line = [self viewWithTag:line_tag];
line.hidden = NO;
CABasicAnimation *animation = [JYScanView moveYTime:2 fromY:[NSNumber numberWithFloat:4] toY:[NSNumber numberWithFloat:self.scanW -2] rep:OPEN_MAX];
[line.layer addAnimation:animation forKey:@"LineAnimation"];
}
+ (CABasicAnimation *)moveYTime:(float)time fromY:(NSNumber *)fromY toY:(NSNumber *)toY rep:(int)rep{
CABasicAnimation *animationMove = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
[animationMove setFromValue:fromY];
[animationMove setToValue:toY];
animationMove.duration = time;
animationMove.delegate = self;
animationMove.repeatCount = rep;
animationMove.fillMode = kCAFillModeForwards;
animationMove.removedOnCompletion = NO;
animationMove.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
return animationMove;
}
/**
* 去除掃碼動畫
*/
- (void)removeAnimation{
UIView *line = [self viewWithTag:line_tag];
[line.layer removeAnimationForKey:@"LineAnimation"];
line.hidden = YES;
}
/**
* 開始掃碼
*/
- (void)startRunning{
[session startRunning];
}
/**
* 結束掃碼
*/
- (void)stopRunning{
[session stopRunning];
}
/**
* 開啟/關閉手電筒
*/
- (void)clickLightBtn:(UIButton *)sender {
Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
if (captureDeviceClass != nil) {
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if ([device hasTorch] && [device hasFlash]){
[device lockForConfiguration:nil];
if (!sender.selected) {
[device setTorchMode:AVCaptureTorchModeOn];
[device setFlashMode:AVCaptureFlashModeOn];
sender.selected = YES;
} else {
[device setTorchMode:AVCaptureTorchModeOff];
[device setFlashMode:AVCaptureFlashModeOff];
sender.selected = NO;
}
[device unlockForConfiguration];
}
}
}
/**
* 移除監聽
*/
- (void)dealloc{
[session removeObserver:self forKeyPath:@"running"];
}
@end