iOS-オリジナルフレームを使ってスイープ機能を実現

11456 ワード

システムのフレームワークを利用してスイープ機能を実現します.
機能を実現する前の項目構成
このアイテムはカメラとアルバムに使うためです.だから、私たちはinfo.plistに訪問を許可するかどうかを問い合わせる権限を設定します.カメラを呼び出す必要がありますので、本物のマシンで運転します.
機能分析
機能の需要分析から、この機能をスキャンすると、以下のいくつかの機能点に分けられます.
  • は、デバイスを起動するときに、loading view
  • を設定する.
  • CGContactextRefを使用して、第一スキャニングインターフェースUI
  • を描画する.
  • NSTimerを用いたスキャンラインアニメーション
  • を実現する.
  • AVFoundationフレームを使ってスキャン機能を実現する
  • は、二次元コード画像をスキャンすることを実現し(システムは二次元コードだけをサポートし、バーコードはサポートしない)、システムフラッシュ
  • を起動する.
  • は、スキャンが完了したら前のインターフェース(Block逆方向転送値)
  • に値を伝える.
    具体的に実現する
  • デバイスを起動するときに、loading view 1を設定します.UIActivityIndicatorViewを引き継ぐLoadViewを作成します.mファイルに初期化コードを書きます.
  • - (id)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            //        
            self.frame = CGRectMake((ScreenWidth - 100)/2, (ScreenHeight - 100)/2, 100, 100);
            //       
            self.backgroundColor = [UIColor blackColor];
            self.layer.cornerRadius = 10;
            //         (  、   、  )
            self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
            //          
            UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, 60, 80, 40)];
            label.text = @"loading...";
            label.font = [UIFont systemFontOfSize:14];
            label.textAlignment = NSTextAlignmentCenter;
            label.textColor = [UIColor whiteColor];
            [self addSubview:label];
        }
        return  self;
    }
    
    2.LoadViewをbgViewに追加する:
    - (void)setupBgView {
        _bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, ScreenWidth, ScreenHeight)];
        _bgView.backgroundColor = [UIColor blackColor];
        
        LoadView *loadView = [[LoadView alloc]init];
        [_bgView addSubview:loadView];
        //     
        [loadView startAnimating];
    }
    
  • .CGContactextRefを使用して、インターフェースUIをスキャンする1.UID Viewを引き継ぐScanViewを作成し、mファイルに次の描画コードを書き込みます.
  • - (void)drawRect:(CGRect)rect {
        CGFloat rectWidth = 50;
        CGFloat rectHeight = 200;
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGFloat black[4] = {0.0, 0.0, 0.0, _alphaValue};
        CGContextSetFillColor(context, black);
        //top
        CGRect rect1 = CGRectMake(0, 0, self.frame.size.width, rectHeight);
        CGContextFillRect(context, rect1);
        //left
        rect1 = CGRectMake(0, rectHeight, rectWidth, rectHeight);
        CGContextFillRect(context, rect1);
        //bottom
        rect1 = CGRectMake(0, rectHeight * 2, self.frame.size.width, self.frame.size.height - rectHeight * 2);
        CGContextFillRect(context, rect1);
        //right
        rect1 = CGRectMake(self.frame.size.width - rectWidth, rectHeight, rectWidth, rectHeight);
        CGContextFillRect(context, rect1);
        CGContextStrokePath(context);
        
        //     (   )
        CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
        CGContextSetLineWidth(context, 1);
        CGContextAddRect(context, CGRectMake(rectWidth, rectHeight, self.frame.size.width - rectWidth * 2, rectHeight));
        CGContextStrokePath(context);
        
        CGFloat lineWidth = 10;
        
        CGContextSetStrokeColorWithColor(context, [UIColor greenColor].CGColor);
        CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
        
        // Draw them with a 2.0 stroke width so they are a bit more visible.
        CGContextSetLineWidth(context, 2.0);
        //      
        CGContextMoveToPoint(context, rectWidth, rectHeight);
        CGContextAddLineToPoint(context, rectWidth + lineWidth, rectHeight);
        
        //      
        CGContextMoveToPoint(context, rectWidth, rectHeight);
        CGContextAddLineToPoint(context, rectWidth, rectHeight + lineWidth);
        
        //      
        CGContextMoveToPoint(context, rectWidth, rectHeight * 2);
        CGContextAddLineToPoint(context, rectWidth + lineWidth, rectHeight * 2);
        
        //      
        CGContextMoveToPoint(context, rectWidth, rectHeight * 2 - lineWidth);
        CGContextAddLineToPoint(context, rectWidth, rectHeight * 2);
    
        //      
        CGContextMoveToPoint(context, self.frame.size.width - rectWidth - lineWidth, rectHeight);
        CGContextAddLineToPoint(context, self.frame.size.width - rectWidth, rectHeight);
        
        //      
        CGContextMoveToPoint(context, self.frame.size.width - rectWidth, rectHeight);
        CGContextAddLineToPoint(context, self.frame.size.width - rectWidth, rectHeight + lineWidth);
    
        //      
        CGContextMoveToPoint(context, self.frame.size.width - rectWidth - lineWidth, rectHeight * 2);
        CGContextAddLineToPoint(context, self.frame.size.width - rectWidth, rectHeight * 2);
        //      
        CGContextMoveToPoint(context, self.frame.size.width - rectWidth, rectHeight * 2 - lineWidth);
        CGContextAddLineToPoint(context, self.frame.size.width - rectWidth, rectHeight * 2);
        CGContextStrokePath(context);
    }
    
    2.scanViewをself.viewに追加する:
    - (void)setupScanView {
        _scan = [[ScanView alloc]initWithFrame:self.view.bounds];
        _scan.backgroundColor = [UIColor clearColor];
        
        _slideLineView = [[UIView alloc]initWithFrame:CGRectMake(_viewWidth, 201, ScreenWidth - _viewWidth * 2, 1)];
        _slideLineView.backgroundColor = [UIColor greenColor];
        [_scan addSubview:_slideLineView];
        [self.view addSubview:_scan];
        [self setupSubView];
    }
    
    3.self.viewのフラッシュボタンとアルバム訪問ボタンを設定する:
    - (void)setupSubView {
        _titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 500, ScreenWidth, 50.0)];
        _titleLabel.text = @"         ";
        _titleLabel.textAlignment = NSTextAlignmentCenter;
        _titleLabel.textColor = [UIColor whiteColor];
        [_scan addSubview:_titleLabel];
        
        _lightButton = [[UIButton alloc]initWithFrame:CGRectMake(100, 580, 50, 50)];
        [_lightButton setTitle:@"light" forState:UIControlStateNormal];
        [_lightButton addTarget:self action:@selector(lightButtonDidTouch) forControlEvents:UIControlEventTouchUpInside];
        [_scan addSubview:_lightButton];
        
        _imageButton = [[UIButton alloc]initWithFrame:CGRectMake(200, 580, 50, 50)];
        [_imageButton setTitle:@"  " forState:UIControlStateNormal];
        [_imageButton addTarget:self action:@selector(imageButtonDidTouch) forControlEvents:UIControlEventTouchUpInside];
        [_scan addSubview:_imageButton];
    }
    
    4.フラッシュボタンのクリックイベント:
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        if (![device hasTorch]) {
            NSLog(@"no torch");
        }else {
            [device lockForConfiguration:nil];
            if (!self.isOpen) {
                [device setTorchMode: AVCaptureTorchModeOn];
                self.isOpen = YES;
            }
            else {
                [device setTorchMode: AVCaptureTorchModeOff];
                self.isOpen = NO;
            }
            [device unlockForConfiguration];
        }
    
    5.アルバムボタンにアクセスするクリックイベント:
    - (void)imageButtonDidTouch {
        [_timer invalidate];
        _timer = nil;
        
        UIImagePickerController *picker = [[UIImagePickerController alloc]init];
        //     (  )
        picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
        //    
        picker.delegate = self;
        //      
        picker.allowsEditing = YES;
        //       
        [self presentViewController:picker animated:YES completion:nil];
    }
    
    #pragma mark UIImagePickerControllerDelegate methods
    //      
    -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
        //      
        [picker dismissViewControllerAnimated:YES completion:nil];
        //   URL  CIImage
        CIImage *ciImage = [[CIImage alloc]initWithCGImage:image.CGImage];
        if (ciImage){
            //   CIDetector
            CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy: CIDetectorAccuracyHigh }];
            NSArray *features = [detector featuresInImage:ciImage];
            if ([features count] > 0) {
                for (CIFeature *feature in features) {
                    if (![feature isKindOfClass:[CIQRCodeFeature class]]) {
                        continue;
                    }
                    CIQRCodeFeature *qrFeature = (CIQRCodeFeature *)feature;
                    NSString *code = qrFeature.messageString;
                    if (self.resultBlock) {
                        self.resultBlock(code);
                        [self scanSuccess];
                    }
                    //       
                    [self.navigationController popViewControllerAnimated:YES];
                }
            }else {
                [self setupTimer];
            }
        }
    }
    //      
    -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
        [picker dismissViewControllerAnimated:YES completion:nil];
    }
    
  • NSTimerを用いて走査線アニメーションを実現するスキャンコードは、以下の通りである.
    - (void)setupTimer {
        _timer = [NSTimer scheduledTimerWithTimeInterval:1.8 target:self selector:@selector(animationView) userInfo:nil repeats:YES];
        [_timer fire];
    }
    
    - (void)animationView {
        [UIView animateWithDuration:1.5 animations:^{
            _slideLineView.transform = CGAffineTransformMakeTranslation(0, 200);
        } completion:^(BOOL finished) {
            _slideLineView.transform = CGAffineTransformIdentity;
        }];
    }
    
  • AVFoundationを使ってスキャン機能を実現する1.AVCapture Metadata Output Objects Delegateを遵守する.初期化コードは以下の通りです.
  • - (void)setupAVFoundation {
        //      
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        //     
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
        //     
        AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init];
        //            
        [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        //       
        _session = [[AVCaptureSession alloc]init];
        //      
        [_session setSessionPreset:AVCaptureSessionPresetHigh];
        [_session addInput:input];
        [_session addOutput:output];
        //           (             )
        output.metadataObjectTypes=@[AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
        
        _previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
        _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        _previewLayer.frame = self.view.layer.bounds;
        [self.view.layer insertSublayer:_previewLayer atIndex:0];
        //    
        [_session startRunning];
        //  loading view
        [_bgView removeFromSuperview];
    }
    
    2.AVCapture Metadata Output Object Delegateを実現する.
    #pragma mark      
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
        if (metadataObjects.count > 0) {
            [_timer invalidate];
            _timer = nil;
            [_session stopRunning];
            AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects objectAtIndex: 0];
            if (self.resultBlock) {
                self.resultBlock(metadataObject.stringValue);
                [self scanSuccess];
            }
            //       
            [self.navigationController popViewControllerAnimated:YES];
        }
    }
    //        
    - (void)scanSuccess {
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        AudioServicesPlaySystemSound(1109);
    }
    
    結尾語
    これで、生フレームを使って二次元コードをスキャンする機能が実現され、原生を使って一つの欠陥があるということは、画像のバーコードをスキャンすることができないということです.この機能を実現するためには、ZXingObjCフレームを使用することができる.プロジェクトの住所、10番目