關于掃描二維碼的一些需求點(掃描二維碼,閃光燈,相冊,動畫)

關于掃描二維碼的一些需求點(掃描二維碼,閃光燈,相冊,動畫)

網上相關的很多,我這里是總結下自己遇到的需求,總共有幾個需求點,

  1. 識別二維碼中的數據
  2. 掃碼動畫
  3. 打開/關閉閃光燈
  4. 取出相冊第一張圖片,點擊可以打開相冊,并識別相冊二維碼
    先給個gif是整體效果圖,估計圖片顯示問題看起來有點卡...


    整體效果

打開相機開始掃描

這個需求最重要的就是打開相機掃描吧,首先先確定你的權限,以及在plist加上這些描述


plist添加描述
另外需要確認是否打開權限如果沒有打開權限直接操作會崩潰的...
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if(status == AVAuthorizationStatusAuthorized) {
        // authorized
        [self setupCamera];
        [self setupLatestAsset];
    } else {
     // alert :@"Tips" message:@"Authorization is required to use the camera, please check your permission settings: Settings> Privacy> Camera" 
    }

1. 識別二維碼中的數據

這里需要導入#import <AVFoundation/AVFoundation.h>主要會用到的有下面的

@property (strong, nonatomic) AVCaptureDevice *device;
@property (strong, nonatomic) AVCaptureDeviceInput *input;
@property (strong, nonatomic) AVCaptureMetadataOutput *output;
@property (strong, nonatomic) AVCaptureSession *session;
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *preview;

其中AVCaptureDevice是設備,AVCaptureDeviceInput是輸入,我的理解就是攝像頭的一些設置,AVCaptureMetadataOutput是輸出,數據輸出,AVCaptureSession我的理解是事務,就是整個流程的事務,AVCaptureVideoPreviewLayer是掃描畫面的圖層.懶加載如下

#pragma mark - lazyMethod
- (AVCaptureDevice *)device
{
    if (!_device) {
        _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    }
    return _device;
}
- (AVCaptureDeviceInput *)input
{
    if (!_input) {
        _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
    }
    return _input;
}
- (AVCaptureMetadataOutput *)output
{
    if (!_output) {
        _output = [[AVCaptureMetadataOutput alloc] init];
        
        
    }
    return _output;
}
- (AVCaptureSession *)session
{
    if (!_session) {
        _session = [[AVCaptureSession alloc] init];
        [_session setSessionPreset:AVCaptureSessionPresetHigh];
    }
    return _session;
}
- (AVCaptureVideoPreviewLayer *)preview
{
    if (!_preview) {
        _preview = [AVCaptureVideoPreviewLayer layerWithSession:_session];
        _preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
        _preview.frame =self.view.layer.bounds;
    }
    return _preview;
}

接下來就是上述屬性的設置

    // 鏈接輸入輸出
    if ([self.session canAddInput:self.input]){
        
        [self.session addInput:self.input];
    }
    
    // http://stackoverflow.com/questions/31063846/avcapturemetadataoutput-setmetadataobjecttypes-unsupported-type-found
    if ([self.session canAddOutput:self.output]){
        
        [self.session addOutput:self.output];
        [self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        // 設置條碼類型
        self.output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];
    }
    
    // 添加掃描畫面
    [self.view.layer insertSublayer:self.preview atIndex:0];

另外需要遵守AVCaptureMetadataOutputObjectsDelegate協議,因為你要在這里拿到掃描出二維碼的信息

#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    NSString *stringValue;
    if ([metadataObjects count] > 0){
        //停止掃描
        [self.session stopRunning];
        AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
        stringValue = metadataObject.stringValue;
        NSLog(@"------------%@-----------",stringValue);
    }
}

到了這里其實就已經可以識別二維碼了,另外還有三個小需求(動畫,相冊,閃光燈)

2. 掃碼動畫

動畫這一塊我并不想講的太多,網上其實有很多,除去一些基本的設置外,就是做一個transform.translation.y的動畫,給你的線加上下面這個動畫就ok,很多時候都會寫個kvo來決定動畫開啟,這里見仁見智了

- (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;
}

3. 打開/關閉閃光燈

閃光燈用到的類主要是AVCaptureDevice,還是直接貼方法

// 打開手電筒開關按鈕點擊事件
- (void)torchOnTouchButton:(UIButton *)sender{
    
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {
        
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        // 判斷是否有閃光燈
        if ([device hasTorch]) {
            
            // 請求獨占訪問硬件設備
            [device lockForConfiguration:nil];
            if (sender.tag == 0) {
                
                sender.tag = 1;
                [self.torchButton setTitle:@"關閉閃光燈" forState:UIControlStateNormal];
                [device setTorchMode:AVCaptureTorchModeOn]; // 手電筒開
            }else{
                
                sender.tag = 0;
                [self.torchButton setTitle:@"打開閃光燈" forState:UIControlStateNormal];
                [device setTorchMode:AVCaptureTorchModeOff]; // 手電筒關
            }
            // 請求解除獨占訪問硬件設備
            [device unlockForConfiguration];
        }
    }
}

我這里主要使用button的tag來記錄是否打開情況,另外,記得在頁面關閉是關了閃光燈

4. 取出相冊最新圖片,點擊打開相冊,并識別相冊二維碼

其實我想記錄的原因就是因為最后一個需求,不然上面的其實網上都很多,主要就是去除相冊最新的一張照片,網上的方法都是iOS 7,iOS 8的,在iOS 9之后都過期了.

打開相冊

打開相冊也是需要判斷是否給了權限,萬萬不可不判斷強上,另外彈出系統的照片選擇器之后

// 打開相冊
- (void)openCameralClick:(id)sender {
    // 1.判斷相冊是否可以打開
    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) return;
    // 2. 創建圖片選擇控制器
    UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
    // 3.設置type
    ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    // 4.設置代理
    ipc.delegate = self;
    // 5.modal出這個控制器
    [self presentViewController:ipc animated:YES completion:nil];
}

打開相冊之后,需要實現UIImagePickerControllerDelegate,UINavigationControllerDelegate協議,拿到選擇回來的照片.也許你好奇為什么這里代碼如此之多,因為掃描從相冊中取出的二維碼跟直接用相機還不一樣,需要使用到CIDetector類,這個類貌似人臉識別什么也用,圖片探測器.我也遇到了掃描不出的情況,代碼中注釋github鏈接也基本解決了我遇到的問題

#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
    // 注意: 如果實現了該方法, 當選中一張圖片時系統就不會自動關閉相冊控制器
    [picker dismissViewControllerAnimated:YES completion:nil];
    
    // 1.取出選中的圖片
    UIImage *pickImage = (UIImage *)[info objectForKey:UIImagePickerControllerEditedImage];
    
    if (!pickImage){
       pickImage = (UIImage *)[info objectForKey:UIImagePickerControllerOriginalImage];
    }

//    http://stackoverflow.com/questions/10746212/cidetector-and-uiimagepickercontroller
    int exifOrientation;
    switch (pickImage.imageOrientation) {
        case UIImageOrientationUp:
            exifOrientation = 1;
            break;
        case UIImageOrientationDown:
            exifOrientation = 3;
            break;
        case UIImageOrientationLeft:
            exifOrientation = 8;
            break;
        case UIImageOrientationRight:
            exifOrientation = 6;
            break;
        case UIImageOrientationUpMirrored:
            exifOrientation = 2;
            break;
        case UIImageOrientationDownMirrored:
            exifOrientation = 4;
            break;
        case UIImageOrientationLeftMirrored:
            exifOrientation = 5;
            break;
        case UIImageOrientationRightMirrored:
            exifOrientation = 7;
            break;
        default:
            break;
    }
    
    // 2.從選中的圖片中讀取二維碼數據
    // 2.1創建一個探測器
    self.detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
    
    // 2.2利用探測器探測數據
    CIImage *theCIImage = [[CIImage alloc] initWithImage:pickImage];
//    CIImage *theCIImage = [CIImage imageWithCGImage:pickImage.CGImage];
    NSArray *features = [self.detector featuresInImage:theCIImage options:@{CIDetectorImageOrientation:[NSNumber numberWithInt:exifOrientation]}];
    
    NSLog(@"theCGImage: %@", pickImage.CGImage);
    NSLog(@"theCIImage: %@", theCIImage);
    NSLog(@"arr: %@", features);
    
    // 2.3取出探測到的數據
    for (CIQRCodeFeature *result in features) {
         NSLog(@"%@",result.messageString);
        NSString *urlStr = result.messageString;
    }
}

最后一個問題是取出用戶相冊中最新的一張圖片展示在掃碼界面,這里需要導入#import <Photos/Photos.h>使用到的類是iOS 9之后的PHAsset直接上代碼吧.網上有很多老的代碼,我找來都是過期了,所以在此記錄

    PHFetchOptions *options = [[PHFetchOptions alloc] init];
    PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
    PHAsset *phasset = [assetsFetchResults lastObject];
    PHCachingImageManager *imageManager = [[PHCachingImageManager alloc] init];
    
    [imageManager requestImageForAsset:phasset targetSize:CGSizeMake(300, 300) contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
        
        // 這里的 result 就是用戶最新的image
    }];
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容