閑暇時間做了個條形碼掃描的功能:包括界面的搭建(只能在矩形框內掃描出結果,并且中間清晰 周邊模糊效果)、功能的實現。

一、利用AVFoundation框架屬性設置(5個重要的變量):
<記錄變量>
// 輸入輸出的中間橋梁
@property(nonatomic, strong) AVCaptureSession *session;
// layer
@property(nonatomic, strong) AVCaptureVideoPreviewLayer *layer;
@property(nonatomic, strong) AVCaptureMetadataOutput *output;
1、 初始化設備為視頻設備 AVCaptureDevice *device
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
2、初始化輸入設備是攝像頭視頻設備 AVCaptureDeviceInput *input
NSError *error = nil;
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
// 如果沒有攝像頭,或者攝像頭不可用就調用代理方法傳出錯誤信息
if (error) {
if ([self.delegate respondsToSelector:@selector(openFailureWithError:)]) {
[self.delegate openFailureWithError:error];
NSLog(@"您的手機不支持條形碼掃描");
}
return;
}
3、初始化輸出設備 AVCaptureMetadataOutput *output
AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
// 設置輸出設備的代理 為當前控制器 并且設置隊列為主隊列
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
self.output = output;
4、初始化會話連接對象 AVCaptureSession *session
self.session = [[AVCaptureSession alloc] init];
// 高質量采集率
[_session setSessionPreset:AVCaptureSessionPresetHigh];
[_session addInput:input];
[_session addOutput:output];
// 設置掃碼支持的編碼格式(如下設置為全部條形碼的可能)
output.metadataObjectTypes = @[AVMetadataObjectTypeEAN13Code,
AVMetadataObjectTypeEAN8Code,
AVMetadataObjectTypeUPCECode,
AVMetadataObjectTypeCode39Code,
AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeCode93Code,
AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code];
5、用會話初始化一個能拍照掃描的AVCaptureVideoPreviewLayer *layer 大小是導航條除外屏幕的大小--size是傳入的參數代表著想照射的范圍,本例設置為屏幕的大小
AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
// 設置layer的frame
layer.frame = CGRectMake((SCREENWIDTH - size.width) * 0.5, 64, size.width, size.height - 64);
// 把拍攝的layer添加到主視圖的layer
[self.view.layer addSublayer:layer];
self.layer = layer;
// 開始捕獲圖像
[_session startRunning];
二、界面的搭建(內清外模糊,并且只在矩形框內才能掃描出結果----抽取自定義視圖)
<保存自定義視圖>
@property(nonatomic, weak) PLScanView *scanView; // 掃描視圖
// 視圖布局
PLScanView *scanView = [[PLScanView alloc] initScanView];
scanView.frame = CGRectMake(0, 64, SCREENWIDTH, SCREENHEIGHT - 64);
[self.view addSubview:scanView];
self.scanView = scanView;
在自定的PLScanView(繼承自UIView)的文件中,寫了一個其他文件可以調用的實例方法:
- (instancetype)initScanView;
在這個方法的實現中,添加必要的視圖 并且
視圖背景色必須設置為clearColor,是為了可以看到攝像頭照射的內容。
1、添加視圖
// 1、添加描述信息
UILabel *messageLbl = [[UILabel alloc] init];
messageLbl.text = @"請將條碼置于取景器內進行掃描,距離大約10cm,盡量避免反光,開啟閃光燈等有助于弱光條件下識別";
messageLbl.numberOfLines = 0;
messageLbl.font = [UIFont systemFontOfSize:12.0];
messageLbl.textColor = [UIColor whiteColor];
[self addSubview:messageLbl];
self.messageLbl = messageLbl;
// 2、添加imageView與滾動線
// 2.1 設置中間掃描區(qū)域的背景圖片
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pick_bg.png"]];
//添加到視圖上
[self addSubview:imageView];
self.imageView = imageView;
// 2.2 初始化二維碼的掃描線
UIImageView *lineImageView = [[UIImageView alloc] init];
lineImageView.image = [UIImage imageNamed:@"line.png"];
[imageView addSubview:lineImageView];
self.lineImageView = lineImageView;
//開啟定時器
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(animation) userInfo:nil repeats:YES];
2、在layoutSubviews中設置布局--設置矩形寬250 高150:
- (void)layoutSubviews
{
[super layoutSubviews];
//描述的label
self.messageLbl.frame = CGRectMake(10, 20, self.width - 20, 30);
//設置位置到界面的中間
self.imageView.frame = CGRectMake(self.bounds.size.width * 0.5 - 250 * 0.5, self.bounds.size.height * 0.5 - 150 * 0.5, 250, 150);
// 開始位置
self.lineImageView.frame = CGRectMake(10, 10, 230, 2);
}
3、定時器的實現:
- (void)animation
{
[UIView animateWithDuration:1.8 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
// 最低位置
self.lineImageView.frame = CGRectMake(10, 130, 230, 2);
} completion:^(BOOL finished) {
// 開始位置
self.lineImageView.frame = CGRectMake(10, 10, 230, 2);
}];
}
4、中間清晰 周圍模糊的界面實現,在drawRect中繪制,代碼如下:
// 1 獲得圖形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2 畫整個屏幕的視圖顏色
CGContextSetRGBFillColor(ctx, 40/255.0, 40/255.0, 40/255.0, 0.5);
CGContextFillRect(ctx, CGRectMake(0, 0, self.width, self.height));
// 3 畫中間透明視圖 clearRect
CGRect clearRect = CGRectMake((self.width - 250) * 0.5, (self.height - 150) * 0.5, 250, 150);
CGContextClearRect(ctx, clearRect);
5、在控制器的viewWillAppear中,如果該控制器被pop之后,還要再次可以掃描,那么AVFoundation的5個變量,要依然存在,所以只需要重新調用上文“一”的代碼即可:
if (!self.session.running) {
// 調用代碼一...
}
6、只能在中間區(qū)域內掃描出功能實現rectOfInterest屬性 -- 修正掃描區(qū)域 右上角為坐標原點,但是傳入的值依然按右上角坐標原點的Y/X/H/W進行理解(右上角為原點下的YXHW)
CGFloat scaleY = (SCREENHEIGHT - 150) * 0.5 / SCREENHEIGHT;
CGFloat scaleX = (SCREENWIDTH - 250) * 0.5 / SCREENWIDTH;
CGFloat scaleH = 150 / SCREENHEIGHT;
CGFloat scaleW = 250 / SCREENWIDTH;
self.output.rectOfInterest = CGRectMake(scaleY, scaleX, scaleH, scaleW);
注:關于self.output.rectOfInterest方法,使用解析如下
//這個CGRectMake(Y,X,H,W) 1代表最大值 原點是導航右上角 為起始點
[output setRectOfInterest:CGRectMake(0, 0.5, 0.5, 0.5)];//左上角 1/4 屏幕
[output setRectOfInterest:CGRectMake(0.5, 0.5, 0.5, 0.5)];//左下角 1/4 屏幕
[output setRectOfInterest:CGRectMake(0.5, 0, 0.5, 0.5)]; //右下角 1/4 屏幕
[output setRectOfInterest:CGRectMake(0, 0, 0.5, 0.5)]; //右上角 1/4 屏幕
[output setRectOfInterest:CGRectMake(0.25,0.25, 0.5, 0.5)]; //貌似 中間的感覺?。?!