1. 程式人生 > >ios-實現二維碼掃描功能

ios-實現二維碼掃描功能

在此就簡單的介紹下二維碼掃描功能的實現把

首先先說下思路,我們需要去配置的就是

  1、輸入裝置(用來獲取外界資訊),輸入裝置有攝像頭、麥克風、鍵盤
  2、輸出裝置(將收集到的資訊進行解析去獲取收到的內容)
  3、會話的session(用來連線輸入和輸出的裝置),不然的話你輸入和輸出裝置都是獨立的沒有個連線
  4、展示輸入裝置所採集的資訊

我們可以定義以下的屬性

//1、輸入裝置(用來獲取外界資訊),輸入裝置有攝像頭、麥克風、鍵盤
@property (nonatomic ,strong)AVCaptureDeviceInput *input;

//2、輸出裝置(將收集到的資訊進行解析去獲取收到的內容)
@property (nonatomic ,strong)AVCaptureMetadataOutput *output;

//3、會話的session(用來連線輸入和輸出的裝置)
/**
 AVCaptureSession(捕捉會話管理):它從物理裝置得到資料流(比如攝像頭和麥克風),然後輸出,它可以通過來控制捕捉資料的格式和質量
 */
@property (nonatomic ,strong)AVCaptureSession *session;

//4、展示輸入裝置所採集的資訊,也就是被用於自動顯示相機產生的實時影象
@property (nonatomic ,strong)AVCaptureVideoPreviewLayer *previewlayer;
之後就是進行建立操作
- (IBAction)ScanClick:(id)sender {
    
    //首先先判斷輸入裝置是否可用,獲取的是攝像頭裝置
    
    AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    if(device==nil)
    {
        //設定彈出alertController
        UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"裝置沒有攝像頭" preferredStyle:
        UIAlertControllerStyleAlert];
       
        [alert addAction:[UIAlertAction actionWithTitle:@"確認" style: UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull
          action) {
            
        }]];
        [self presentViewController:alert animated:YES completion:nil];
        return;
    }
    
     //1、輸入裝置(用來獲取外界資訊)
    self.input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    
    //2、輸出裝置(將收集到的資訊進行解析去獲取收到的內容)
    self.output = [AVCaptureMetadataOutput new];
    
    //3、會話的session(用來連線輸入和輸出的裝置)
    self.session = [AVCaptureSession new];
    
    //用於設定output輸出流的bitrate或者說採集的質量
    if([self.session canSetSessionPreset:AVCaptureSessionPresetHigh])
    {
        [self.session setSessionPreset:AVCaptureSessionPresetHigh];
    }
    //捕捉會話管理和輸入輸出裝置進行關聯
    if([self.session canAddInput:self.input])
    {
        [self.session addInput:self.input];
    }
    if([self.session canAddOutput:self.output])
    {
        [self.session addOutput:self.output];
    }
    //指定輸出裝置的代理,用來接收返回的資料,回撥在主佇列中執行
    [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    
    //設定元資料型別 二維碼就是QRCode
    [self.output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
    
    //設定掃描區域的大小
    CGFloat Width = self.view.bounds.size.width;
    CGFloat Height =  self.view.bounds.size.height;
    
    [self.output setRectOfInterest:CGRectMake((Height*0.5 - 140)/Height,(Width * 0.5 - 140)/Width, 280/Height, 280/Width)];
    
    //4、特殊的layer(展示輸入的裝置所採集的資訊),可被用於自動顯示相機產生的實時影象
    self.previewlayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:_session];

    //設定layer的大小,
    self.previewlayer.frame = self.view.bounds;

    //新增layer
    [self.view.layer addSublayer:self.previewlayer];
     
    //啟動會話
    [self.session startRunning];
   }

  //獲取掃描的結果
-(void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects
 fromConnection:(AVCaptureConnection *)connection
{
    //1、停止會話
    [self.session stopRunning];
    
    //2、刪除layer
    [self.previewlayer removeFromSuperlayer];
    
    //3、遍歷資料獲取內容
    for(AVMetadataMachineReadableCodeObject * obj in metadataObjects)
    {
        self.detailLabel.text = obj.stringValue;
    }
    //captureOutput: 輸出裝置的意思
    //metadataObjects: 元資料物件的陣列
    //connection: 連線
    
}
    
這裡需要注意的就是設定掃描區域的大小,它的預設掃描區域時全屏,預設值是(0,0,1,1)

如下圖所示


如果我們要去設定掃描區域的大小也就是去設定setRectOfInterest,裡面傳入的CGRect的x和y和w和h都是0-1。

這裡需要注意的是我們這裡傳入的應該的四個引數應該是Y,X,H,W,右上角是原點,如下圖所示


這裡還有一點需要介紹的是


這裡傳入的陣列多加了個__kindof,__kindof:代表這個數組裡面可以有它本身的類也可以有它的子類,也會被用在方法的返回值,加__kindof修飾後,比如說一個方法的返回值原本是NSArray,但是方法裡邊卻返回了一個NSArray的子類NSMutableArray,也就是說,加__kindof修飾後,本類及其子類都可以返回,呼叫使用時也可以使用本類或者

子類去接收方法的返回值。我們可以看到蘋果對於下面這個方法來說,返回值也是加了__kindof

- (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

還有一點要補充的就是下面這個方法

+ (Class)layerClass
{
    return [AVCaptureVideoPreviewLayer class];
}
每一個UIView都有在一個CALayer,這個圖層是由檢視自動建立和管理的,一旦檢視被建立,我們就無法去更改這個layer了。但是如果我們自定義一個view,那我們就可以重寫+layerClass方法使得在建立的時候能返回一個不同的圖層的子類。UIView會在初始化的時候呼叫+layerClass方法,然後用它的返回型別來建立view的layer。