寫這篇文章的主要緣由不是展現如何使用 AVFoundation 來進行二維碼掃描,更主要的是限制掃描二維碼的範圍。(由於默認的是全屏掃描)session
項目遇到掃描二維碼的功能需求,這裏我放棄了使用三方庫,而採用了蘋果原生的掃描。ide
原生的好處就是掃描特別快效率特別高,可是遇到一個問題就是不知道怎麼去限制掃描範圍。優化
仍是先簡單說一下怎麼使用來進行二維碼掃描吧。this
首先是要用到的幾個類atom
@property (strong,nonatomic)AVCaptureDevice * device;spa
@property (strong,nonatomic)AVCaptureDeviceInput * input;.net
@property (strong,nonatomic)AVCaptureMetadataOutput * output;rest
@property (strong,nonatomic)AVCaptureSession * session;orm
@property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview;blog
他們之間的關係能夠看下面的篇文章
下面分別建立他們
// Device
_device = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];
// Input
_input = [AVCaptureDeviceInputdeviceInputWithDevice:self.deviceerror:nil];
// Output
_output = [[AVCaptureMetadataOutputalloc]init];
[_outputsetMetadataObjectsDelegate:selfqueue:dispatch_get_main_queue()];
// Session
_session = [[AVCaptureSessionalloc]init];
[_sessionsetSessionPreset:AVCaptureSessionPresetHigh];
if ([_sessioncanAddInput:self.input])
{
[_sessionaddInput:self.input];
}
if ([_sessioncanAddOutput:self.output])
{
[_sessionaddOutput:self.output];
}
// 條碼類型 AVMetadataObjectTypeQRCode
_output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];
// Preview
_preview =[AVCaptureVideoPreviewLayerlayerWithSession:_session];
_preview.videoGravity =AVLayerVideoGravityResizeAspectFill;
_preview.frame =self.view.layer.bounds;
[self.view.layerinsertSublayer:_previewatIndex:0];
// Start
[_sessionstartRunning];
而後實現 AVCaptureMetadataOutputObjectsDelegate
#pragma mark AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
NSString *stringValue;
if ([metadataObjectscount] >0)
{
//中止掃描
[_sessionstopRunning];
AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjectsobjectAtIndex:0];
stringValue = metadataObject.stringValue;
}
}
到此爲止就能夠成功掃描二維碼了,可是有個尷尬的問題,這時的掃描是全屏掃描的。即
通常狀況下項目中的掃描頁面是這樣的,可是當你掃描的時候會發如今二維碼還沒進入中心的那個小方塊時,就已經成功掃描完成了,這對於體驗來講很很差。可是因爲那時候趕項目就沒有時間優化。終於今天抽出來時間了。
我從早上上班開始一直搞到下午,把全部想到的方法都試了一遍,可是都不行(都是淚),最後將要放棄的時候發現了一個比較可疑的點。
@property(nonatomic)CGRect rectOfInterest NS_AVAILABLE_IOS(7_0);
@discussion
The value of this property is a CGRect that determines the receiver's rectangle of interest for each frame of video.
The rectangle's origin is top left and is relative to the coordinate space of the device providing the metadata. Specifying
a rectOfInterest may improve detection performance for certain types of metadata. The default value of this property is the
value CGRectMake(0, 0, 1, 1). Metadata objects whose bounds do not intersect with the rectOfInterest will not be returned.
大概意思就是設置每一幀畫面感興趣的區域(字面意思),那豈不是就是設置掃描範圍嘍,大喜
[_outputsetRectOfInterest:CGRectMake((ScreenWidth-220)/2,60+64,220, 220)];
//中間區域的寬和高都是220 ScreenWidth爲設備屏幕寬度
[_outputsetRectOfInterest:CGRectMake(((ScreenWidth-220)/2)/ScreenWidth,(60+64)/ScreenHigh,220/ScreenWidth,220/ScreenHigh)];
按說這樣應該就完美了,可是才知道我仍是高興得太早了,一掃描才發現徹底不是那麼回事,差不少。
因而我就一點一點調,可是最後也沒調成功,最後一狠心有設置了一個很肯定的值。
[_output setRectOfInterest:CGRectMake(0.5,0.5,0.5, 0.5)];
此次應該很肯定是在右下方的四分之一區域吧,嘿嘿。
可是事實又一次打擊了我,掃描後發現是左下的四分之一區域,也就是說rectOfInterest的原點是右上角!!!
回頭又一想,即便右上角是原點那也應該沒有影響啊,可是爲何不行呢,不會是原點的 X 和 Y 互換了吧?算了無論怎麼着,試一試吧。
[_outputsetRectOfInterest:CGRectMake((60+64)/ScreenHigh,((ScreenWidth-220)/2)/ScreenWidth,220/ScreenWidth,220/ScreenHigh)];
又掃描了一下發現成功了!果真原點正確了,我只想說TMD!
可是寬和高又怎麼對不上了?不會也互換了吧!趕忙試試
[_outputsetRectOfInterest:CGRectMake((124)/ScreenHigh,((ScreenWidth-220)/2)/ScreenWidth,220/ScreenHigh,220/ScreenWidth)];
因而用系統原生的掃描二維碼就完美了!
原文連接:http://blog.csdn.net/lc_obj/article/details/41549469