美文网首页
原生二维码扫描

原生二维码扫描

作者: Coder东 | 来源:发表于2017-04-20 15:53 被阅读24次

    import "ScanViewController.h"

    #import <AVFoundation/AVFoundation.h>
    #import "LayoutView.h"
    
    #define kZero 0
    #define kFullScreen [UIScreen mainScreen].bounds
    #define kFullWidth [UIScreen mainScreen].bounds.size.width
    #define kFullHeight [UIScreen mainScreen].bounds.size.height
    
    @interface ScanViewController ()    <AVCaptureMetadataOutputObjectsDelegate>
    
    @property (nonatomic ,strong) AVCaptureSession *session;
    @property (nonatomic, assign) BOOL isOpenFlashlight;//是否打开闪光灯
    
    @end
    
    @implementation ScanViewController
    -(void)isOpenFlashLight:(UIButton *)btn{
    self.isOpenFlashlight = !self.isOpenFlashlight;
     AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    
    if (self.isOpenFlashlight) {//打开闪光灯
        if (device.torchMode == AVCaptureTorchModeOff) {//torch手电筒模式
              AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
            if (device.position == AVCaptureDevicePositionFront){
                    return;
                }else{
                    [device lockForConfiguration:nil];//设备锁
                    [device setTorchMode:AVCaptureTorchModeOn];//手电筒打开
                    [device unlockForConfiguration];//不需要自动调用
                }
            
        }
    }else{
        if (device.torchMode == AVCaptureTorchModeOn) {//手电筒打开
            [device lockForConfiguration:nil];
            [device setTorchMode:AVCaptureTorchModeOff];
            [device unlockForConfiguration];
        }
    }
    
    
    
    }
    //FIXME:MARK --- 摄像头前后切换 --
    -(void)switchCameraBtnClick:(UIButton *)btn {
    [self swapFontAndBackCameras];
    }
    //FIXME:MARK -- 是否有摄像头 ---
    -(BOOL)isCameraAvaliable {
    return [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
    }
    //FIXME:MARK -- 前置摄像头是否可用 --
    - (BOOL)isFrontCameraAvailable {
    
    return [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront];
    }
    //FIXME:MARK -- 后置摄像头是否可用--
    -(BOOL)isRearCameraAvailable {
    return [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear];
    }
    //FIXME:MARK -- 是否有其他摄像设备 --
    -(BOOL)hasMultipleCameras {
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    if (devices != nil && [devices count] > 1) {
        return YES;
    }else{
        return NO;
    }
    }
    //FIXME:MARK -- 设备方向 --
    -(AVCaptureDevice *)cameraWithPositon:(AVCaptureDevicePosition )position {
    
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in devices ) {
        if (device.position == position) {
            return device;
        }
    }
        return nil;
    }
    //FIXME:MARK -- 设置摄像头方向--
    -(void)swapFontAndBackCameras {
    
    if (![self hasMultipleCameras]) {
        return;
    }
    
    NSArray *inputs = self.session.inputs;
    for (AVCaptureDeviceInput *input in inputs) {
        AVCaptureDevice *device = input.device;
        if ([device hasMediaType:AVMediaTypeVideo]) {
            
            AVCaptureDevicePosition position = device.position;
            AVCaptureDevice *newCamera = nil;
            AVCaptureDeviceInput *newInput = nil;
            
            if (position == AVCaptureDevicePositionFront){
                //前置状态闪光等自动关闭
                if (device.torchMode == AVCaptureTorchModeOn) {
                    [device setTorchMode:AVCaptureTorchModeOff];
                }else{
                    NSLog(@"do nothing");
                }
                 newCamera = [self cameraWithPositon:AVCaptureDevicePositionBack];
            }
            else{
                newCamera = [ self cameraWithPositon:AVCaptureDevicePositionFront];
                
               
            }
             newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
            
            [self.session beginConfiguration];
            [self.session removeInput:input];
            [self.session addInput:newInput];
            
            //提交 防止配置无效
            [self.session commitConfiguration];
            break;
        }
        
    }
    }
    - (void)viewDidLoad {
    [super viewDidLoad];
    //是否开启闪光灯
    self.isOpenFlashlight = NO;
    self.automaticallyAdjustsScrollViewInsets = NO;
    
    //相机授权
    [self checkAVAuthorizationStatus];
    
    LayoutView *layout = [[LayoutView alloc]initWithFrame:CGRectMake(kZero, 64, kFullWidth, kFullHeight - 64)];
    [self.view addSubview:layout];
    
    
    UIButton *flashBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [flashBtn setTitle:@"闪光灯" forState:UIControlStateNormal];
    flashBtn.frame = CGRectMake(80, kFullHeight - 70, 60, 40);
    [flashBtn addTarget:self action:@selector(isOpenFlashLight:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:flashBtn];
    
    UIButton *switchCameraBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [switchCameraBtn setTitle:@"前后切换" forState:UIControlStateNormal];
    switchCameraBtn.frame = CGRectMake(180, kFullHeight - 70, 60, 40);
    [switchCameraBtn addTarget:self action:@selector(switchCameraBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:switchCameraBtn];
    
    //呈现图片的一个图层
    AVCaptureVideoPreviewLayer *layer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    layer.frame = self.view.layer.bounds;
    [self.view.layer insertSublayer:layer atIndex:0];
    
                                         
    }
    
    /*
    *  AVAuthorizationStatus
    *
    *  @param  AVAuthorizationStatusRestricted         授权请求
     *  @param  AVAuthorizationStatusDenied             授权失败
     *  @param  AVAuthorizationStatusAuthorized         授权成功
     */
    
    -(void)checkAVAuthorizationStatus{
    
    AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (status == AVAuthorizationStatusRestricted) {
        //客户端未授权
        
    }else if (status == AVAuthorizationStatusDenied){
        //用户明确拒绝访问
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"请在设置中开启照相机权限" message:nil preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
            
        }];
        [alertVC addAction:action];
        [self presentViewController:alertVC animated:YES completion:nil];
    }else if (status == AVAuthorizationStatusAuthorized){
        //授权
    }
    }
    -(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.session startRunning];
    self.tabBarController.tabBar.hidden = YES;
    }
    -(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.session stopRunning];
    }
    -(AVCaptureSession *)session{
    if (!_session) {
        //获取摄像设备
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        //创建输入流
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
        if (!input) {
            return  nil;
        }
        //创建输出流
        AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init];
        //设置代理,在主线程里刷新
        [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
        //设置扫描区域的比例
        CGFloat width = 300/CGRectGetWidth(self.view.bounds);
        CGFloat height = 300/CGRectGetHeight(self.view.bounds);
        //此属性的值是一个CGRect指定一个rectofinterest可能提高某些类型的元数据的检测性能。此属性的默认值是价值cgrectmake(0,0,1,1)。元数据对象的边界不与rectofinterest相交将不会返回
    #warning rectOfInterest --> (y,x,height,width)且默认(0,0,1,1)
    
        output.rectOfInterest = CGRectMake((1-height)/2, (1-width)/2, height, width);
        
        self.session = [[AVCaptureSession alloc]init];
        //高质量采集率
        [self.session setSessionPreset:AVCaptureSessionPresetHigh];
        [self.session addInput:input];
        [self.session addOutput:output];
        
        //设置扫码支持的编码格式(条形码和二维码兼容)
        output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode,
                                       AVMetadataObjectTypeEAN13Code,
                                       AVMetadataObjectTypeEAN8Code,
                                       AVMetadataObjectTypeCode128Code];
    }
    return _session;
    }
    pragma mark **** AVCaptureMetadataOutputObjectsDelegate
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    NSLog(@"%@",metadataObjects);
    if (metadataObjects.count > 0) {
        [self.session stopRunning];
        
        AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects firstObject];
    #pragma mark * 扫描结果事件
        UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"扫码结果" message:[metadataObject stringValue] preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
            [self.session startRunning];
        }];
        [alertC addAction:action];
        [self presentViewController:alertC animated:YES completion:nil];
    }
    }
    
    @end
    

    02.滚动线的View的编写

    #import "LayoutView.h"
    
    @interface LayoutView ()
    
    @property (nonatomic, strong) CALayer *lineLabyer;
    
    
    @end
    
    @implementation LayoutView
    
    -(instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        [self setLayoutView];
    }
    return self;
    }
    //重绘view方法
    -(void)drawRect:(CGRect)rect{
    
    CGFloat width = rect.size.width;
    CGFloat height = rect.size.height;
    CGFloat pickingFieldWidth = 300;//采集信息区域的大小
    CGFloat pickingFieldHieght = 300;
    
    //创建上下文
    CGContextRef contectRef = UIGraphicsGetCurrentContext();
    //将当前图形状态推入堆栈,之后,您对图形状态所做的修改会影响随后的描画操作,但不影响存储在堆栈中的拷贝
    CGContextSaveGState(contectRef);
    //设置填充颜色
    CGContextSetRGBFillColor(contectRef, 0, 0, 0, 0.35);
    //线的宽度
    CGContextSetLineWidth(contectRef, 3);
    
    CGRect pickingFieldRect = CGRectMake((width-pickingFieldWidth)/2, (height-pickingFieldWidth)/2, pickingFieldWidth, pickingFieldHieght);
    //根据一个矩形划线
    UIBezierPath *pickingFieldPath = [UIBezierPath bezierPathWithRect:pickingFieldRect];
    UIBezierPath *bezierPathRect = [UIBezierPath bezierPathWithRect:rect];
    
    [bezierPathRect appendPath:pickingFieldPath];
    
    
    //填充使用奇偶法则(NO为非0法则)
    bezierPathRect.usesEvenOddFillRule = YES;
    //填充
    [bezierPathRect fill];
    CGContextSetLineWidth(contectRef, 2);
    CGContextSetRGBStrokeColor(contectRef, 27/255.0, 181/255.0, 254/255.0, 1);
    
    [pickingFieldPath stroke];//划线
    CGContextRestoreGState(contectRef);
    //集中在水平和垂直方向的矩形
    self.layer.contentsGravity = kCAGravityCenter;
    
    }
    -(void)setLayoutView{
    
    self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
    self.lineLabyer = [CALayer layer];
    self.lineLabyer.contents = (__bridge id _Nullable)(([UIImage imageNamed:@"line"].CGImage));
    [self.layer addSublayer:self.lineLabyer];
    
    [self resumeAnimation];
    
    
    self.lineLabyer.frame = CGRectMake((self.frame.size.width - 300)/2, (self.frame.size.height - 300)/2, 300, 2);
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeAnimation) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stopAnimation) name:UIApplicationDidEnterBackgroundNotification object:nil];
    
    }
    
    -(void)resumeAnimation{
    
    CABasicAnimation *basic = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    basic.fromValue = @(0);
    basic.toValue = @(300);
    basic.duration = 1.5;
    basic.repeatCount = NSIntegerMax;
    [self.lineLabyer addAnimation:basic forKey:@"translationY"];
    }
    -(void)stopAnimation{
    [self.lineLabyer removeAnimationForKey:@"translationY"];
    }
    @end
    

    相关文章

      网友评论

          本文标题:原生二维码扫描

          本文链接:https://www.haomeiwen.com/subject/xyelzttx.html