iOS 二維碼窗口

iOS 學習日誌 : iOS原生二維碼的掃描以及限定掃描範圍,有需要的朋友可以參考下。



現在的app多少都會加入二維碼掃描功能,方便快捷,開發中常常會碰到這樣的需求.



定義會話和輸出流對象





@property (nonatomic) AVCaptureSession *captureSession;
@property (nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer;




// 獲取 AVCaptureDevice 實例
    NSError * error;
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    // 初始化輸入流
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    if (!input) {
        NSLog(@"%@", [error localizedDescription]);
        return NO;
    }
    // 創建會話
    _captureSession = [[AVCaptureSession alloc] init];
    // 添加輸入流
    [_captureSession addInput:input];
    // 初始化輸出流
    AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];

    // 添加輸出流
    [_captureSession addOutput:captureMetadataOutput];

    // 創建dispatch queue.
    dispatch_queue_t dispatchQueue;
    dispatchQueue = dispatch_queue_create(kScanQRCodeQueueName, NULL);
    [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
    // 設置數據類型 AVMetadataObjectTypeQRCode
    [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];

    // 創建輸出對象
    _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [_videoPreviewLayer setFrame:self.view.bounds];
    [self.view.layer addSublayer:_videoPreviewLayer];
    // 開始會話
    [_captureSession startRunning];


這裏準備工作就做完了,在startRunning後就會開啓二維碼的掃描,然後遵守AVCaptureMetadataOutputObjectsDelegate代理 ,在代理方法中處理掃碼獲得的數據



-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
      fromConnection:(AVCaptureConnection *)connection
{
    if (metadataObjects != nil && [metadataObjects count] > 0) {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        NSString *result;
        [_captureSession stopRunning];
        if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            result = metadataObj.stringValue;
        } else {
            NSLog(@"不是二維碼");
        }

    }
}


這樣最基礎的二維碼掃描就做完了,但是用戶體驗並不好,因爲默認的是全屏掃描,而且原生的二維碼掃描很快,容易誤操作,影響用戶體驗.



所以我們需要限定掃描的範圍,AVCaptureMetadataOutput 有對應的屬性設置掃描範圍,但是它的座標系有些特殊 並不是常見的(x,y,width,height)而是(y,x,height,width),所以就需要將座標翻轉過來,下面是一個左右間距各50,居中的正方形掃描框,那麼就將掃描範圍限定在這個掃描框裏。 

AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init]; 

[captureMetadataOutput setRectOfInterest:CGRectMake(([UIScreen mainScreen].bounds.size.height/2-([UIScreen mainScreen].bounds.size.width-100)/2)/ 

[UIScreen mainScreen].bounds.size.height,50/[UIScreen mainScreen].bounds.size.width, ([UIScreen mainScreen].bounds.size.width-100)/[UIScreen mainScreen].bounds.size.height, ([UIScreen mainScreen].bounds.size.width-100)/[UIScreen mainScreen].bounds.size.width)];



最後嘛 可以利用view的動畫來完成掃描框的線性”掃描”,提升用戶體驗



下面是利用masory約束的一個 左右間距50並居中的掃描框,然後利用動畫完成線性的掃描,欺騙用戶…….0.0





UIView * anniView= [[UIView alloc]init];
    anniView.tag = 111;
    [self.view addSubview:anniView];
    [anniView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerX.equalTo(self.view.mas_centerX);
        make.centerY.equalTo(self.view.mas_centerY);
        make.left.equalTo(self.view).with.offset(50);
        make.right.equalTo(self.view).with.offset(-50);
        make.width.equalTo(anniView.mas_height);
    }];
    //掃描框
    UIImageView * imageView = [[UIImageView alloc]init];
    [anniView addSubview:imageView];
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(anniView).insets(UIEdgeInsetsMake(0, 0, 0, 0));
    }];
    imageView.image = [UIImage imageNamed:@"cornround"];
    //掃描線
    UIImageView * line = [[UIImageView alloc]init];
    [anniView insertSubview:line aboveSubview:imageView];
    line.backgroundColor = [UIColor clearColor];
    line.image = [UIImage imageNamed:@"line"];
    [line mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(anniView).with.offset(0);
        make.right.equalTo(anniView).with.offset(0);
        make.top.equalTo(anniView).with.offset(0);
        make.height.equalTo(@2);
    }];
    CABasicAnimation *animationMove = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    [animationMove setFromValue:@(0)];
    [animationMove setToValue:@([UIScreen mainScreen].bounds.size.width-102)];
    animationMove.duration = 5.0f;
    animationMove.delegate = self;
    animationMove.repeatCount  = OPEN_MAX;
    animationMove.removedOnCompletion = NO;
    animationMove.fillMode = kCAFillModeForwards;
    animationMove.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [line.layer addAnimation:animationMove forKey:animationKey];


最後在掃碼獲取到數據之後,停止掃描.並根據tag值獲取UIImageView 移除動畫,並把掃描框從當前視圖中移除

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章