二維碼掃碼效果(多個(gè)二維碼識(shí)別和點(diǎn)選)

類似微信掃碼效果,會(huì)標(biāo)記識(shí)別到的二維碼震蒋,并且識(shí)別到多個(gè)二維碼時(shí)走孽,可以允許用戶點(diǎn)選敛腌。

二維碼坐標(biāo)解析步驟:

1攝像頭掃描

首先說明:攝像頭獲取的視頻流和屏幕尺寸比例不一定一樣,獲取的二維碼坐標(biāo)及角點(diǎn)是以視頻流的坐標(biāo)系為基準(zhǔn)的比例值(范圍0-1)搬男。
本次代碼以videoPreviewLayer(用于展示攝像頭捕獲的視頻流)frame設(shè)為全屏,setVideoGravity參數(shù)設(shè)為AVLayerVideoGravityResizeAspectFill為例進(jìn)行說明。


左邊的計(jì)算差值傻铣,右邊的計(jì)算需要補(bǔ)值,原理一樣

掃描代理方法返回的數(shù)據(jù)為AVMetadataMachineReadableCodeObject數(shù)組(若是設(shè)置為人臉掃描等其它模式祥绞,則返回對(duì)應(yīng)類型的數(shù)組)
AVMetadataMachineReadableCodeObject關(guān)鍵屬性:
type:數(shù)據(jù)類型(二維碼矾柜,條形碼等碼類型);
stringValue:二維碼或條形碼的值就谜;
bounds:二維碼在源視頻流對(duì)應(yīng)的幀圖像中的位置和大小怪蔑。
corners:二維碼的四個(gè)角的點(diǎn)坐標(biāo)。
其中bounds和corners的基準(zhǔn)坐標(biāo)系是視頻源中對(duì)應(yīng)的幀畫面坐標(biāo)系丧荐。
我們主要用corners來計(jì)算二維碼在videoPreviewLayer上顯示的位置及對(duì)應(yīng)的視圖坐標(biāo)系下的frame缆瓣。
然后添加透明遮罩層在對(duì)應(yīng)的位置添加按鈕及點(diǎn)擊事件。

計(jì)算位置的具體步驟為:

評(píng)論區(qū)有說系統(tǒng)自帶方法是可以直接計(jì)算frame的:transformedMetadataObjectForMetadataObject方法
有驗(yàn)證過的可以在評(píng)論區(qū)補(bǔ)充~

//在這個(gè)方法里面:
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    AVMetadataObject *newObj = [connection.videoPreviewLayer transformedMetadataObjectForMetadataObject:obj];
    //newObj.bounds 就是轉(zhuǎn)為app坐標(biāo)系的了虹统。
}
//connection

以上方法可用的話弓坞,下面這步驟可以不用看了。
1车荔,獲取差值渡冻。

初始坐標(biāo)系,以iphoneXS流分辨率720*1280為例和屏幕尺寸有差值

2忧便,交換X族吻,Y軸。

3珠增,翻轉(zhuǎn)X軸超歌。

4,帶入差值計(jì)算(若是其它填充方式則需要修改差值計(jì)算蒂教,有可能需要增加補(bǔ)值)

此時(shí)4個(gè)角點(diǎn)坐標(biāo)已轉(zhuǎn)換完畢巍举,但是二維碼不一定與屏幕角度相同,通過角點(diǎn)計(jì)算出二維碼的長(zhǎng)方形范圍坐標(biāo)作為二維碼frame凝垛,并在其中心點(diǎn)添加按鈕:
左邊為理想情況懊悯,右邊為實(shí)際情況,紅色虛線frame即為二維碼坐標(biāo)

具體可看方法:-(CGRect)makeFrameWithCodeObject:(AVMetadataMachineReadableCodeObject *)objc;

2,圖片選擇掃描:

圖片掃描返回的數(shù)據(jù)為:CIQRCodeFeature主要參數(shù):
messageString:碼值梦皮;
bounds:碼位置
其中bounds是二維碼在圖片坐標(biāo)系上的位置炭分,單位是像素,坐標(biāo)系方向受圖片方向影響届氢。
關(guān)于圖片方向:
uiimage方向?qū)傩詉mageOrientation:

typedef NS_ENUM(NSInteger, UIImageOrientation) {
    UIImageOrientationUp,            // default orientation
    UIImageOrientationDown,          // 180 deg rotation
    UIImageOrientationLeft,          // 90 deg CCW
    UIImageOrientationRight,         // 90 deg CW
    UIImageOrientationUpMirrored,    // as above but image mirrored along other axis. horizontal flip
    UIImageOrientationDownMirrored,  // horizontal flip
    UIImageOrientationLeftMirrored,  // vertical flip
    UIImageOrientationRightMirrored, // vertical flip
};

手機(jī)展示圖片時(shí)會(huì)受圖片方向影響欠窒,比如無論是橫持還是豎持甚至倒持手機(jī)拍攝一個(gè)“↑“,在相冊(cè)展示時(shí)箭頭都是朝上的。我們?cè)趇mageView展示時(shí)也是一樣岖妄。但是二維碼識(shí)別返回的數(shù)據(jù)中:
靠近音量調(diào)節(jié)的角為原點(diǎn)(0型将,0)。長(zhǎng)邊為X軸荐虐,短邊為Y軸七兜,二維碼的origin為靠近原點(diǎn)的角
所以需要坐標(biāo)系轉(zhuǎn)換。
默認(rèn)圖片拍攝的坐標(biāo)系為手機(jī)朝左橫持為下圖的樣子(即圖片方向?yàn)閁IImageOrientationUp的圖片福扬,是以下圖手持方向拍攝的)

默認(rèn)UIImageOrientationUp時(shí)的照片方向腕铸,綠點(diǎn)為frame.origin

正常豎屏展示的樣子(正常開發(fā)時(shí)的坐標(biāo)系)及二維碼frame.origin點(diǎn)為:(UIImageOrientationUp的圖片,在app內(nèi)展示的樣子铛碑,及我們需要的origin點(diǎn)的位置)


與上一張圖做比較

對(duì)比后狠裹,我們應(yīng)該要做Y軸反轉(zhuǎn)和比例縮放計(jì)算
y軸翻轉(zhuǎn)計(jì)算:圖片的H-二維碼的H-二維碼的y值。
在計(jì)算圖片縮放比列后就可以得出在正常坐標(biāo)系下二維碼在圖片的位置汽烦。


其它幾種拍照下的坐標(biāo)系示例:


左邊為常用的拍照?qǐng)鼍疤尾ぃ琔IImageOrientationRight。右邊為UIImageOrientationDown

可以看出:
UIImageOrientationRight方向的圖片需要XY交換撇吞,
UIImageOrientationDown方向的需要翻轉(zhuǎn)x值俗冻。
其他屬性可以類推。

另外帶鏡像屬性的圖片暫時(shí)沒有找到牍颈,未做測(cè)試。

代碼部分

.h:

#import <UIKit/UIKit.h>
typedef void(^ScanResultBlock)(NSString* result); //二維碼點(diǎn)選操作
typedef void(^ScanOutputs)(NSArray* results);//@[@{@"code":"",@"frame":@""}]

@interface XYQRScanViewController : UIViewController
@property (strong, nonatomic, readonly) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (assign, nonatomic, readonly) BOOL isScaning;
@property (copy, nonatomic) ScanOutputs scanOutputs;//可選的實(shí)現(xiàn)掃描多個(gè)二維碼后的預(yù)測(cè)操作煮岁。比如自動(dòng)選擇某個(gè)二維碼

- (void)startScan;
- (void)stopScan;

//+ (NSArray <NSDictionary *> *)scanWithImage:(UIImage*)image; //暫未實(shí)現(xiàn)
- (instancetype)initWithScanResultBlock:(ScanResultBlock)block;//二維碼點(diǎn)選操作

@end

.m

.m:

#import "XYQRScanViewController.h"
#import "UIColor+DynamicColor.h"
#import "HDXYScanImageSelectController.h"

#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
#define kDevice_Is_iPhoneX (SCREEN_WIDTH >= 375.f && SCREEN_HEIGHT >= 812.f)
#define kSafeArea_Top (kDevice_Is_iPhoneX? 44: 20 )

@interface XYQRScanViewController ()<AVCaptureMetadataOutputObjectsDelegate, UIImagePickerControllerDelegate,AVCaptureVideoDataOutputSampleBufferDelegate>

@property (nonatomic, strong) UILabel *promptLabel;

@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIView *bottomView;

@property (strong, nonatomic) UIView *myScanBGView;
@property (strong, nonatomic) UIImageView *scanRectView, *lineView;
@property (strong, nonatomic) UILabel *tipLabel;
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (strong, nonatomic) CIDetector *detector;
@property (strong, nonatomic) UIButton *lightButton;
@property (strong,nonatomic)UIButton *photoButton;
@property (strong,nonatomic)UIButton *codeButton;
@property (strong, nonatomic) UIView *topBg;
@property (nonatomic,assign)CGRect scanRect;
@property (nonatomic,strong)UIView *bottomContentView;
@property (nonatomic,strong)UILabel *cricleLabel;
//@property (nonatomic,strong)MLMSegmentHead *segemetHead;
@property (nonatomic,strong)UIButton *popButton;
@property (assign, nonatomic, readwrite) BOOL isScaning;
@property (nonatomic, copy) void(^scanBlock)(NSString *scanStr);//掃碼回調(diào)
@end

@implementation XYQRScanViewController

- (instancetype)initWithScanResultBlock:(ScanResultBlock)block
{
    self = [super init];
    if (self) {
        _scanBlock = block;
    }
    return self;
}

- (CIDetector *)detector{
    if (!_detector) {
        _detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }];
    }
    return _detector;
}

- (void)viewDidLoad {
    [super viewDidLoad];
     UIColor *color = [UIColor colorWithDarkModeColor:BlackColor normalColor:HexF7F8FA];
     self.view.backgroundColor = color;
     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
     
     [nc addObserver:self
            selector:@selector(applicationDidBecomeActive:)
                name:UIApplicationDidBecomeActiveNotification
              object:nil];
     [nc addObserver:self
            selector:@selector(applicationWillResignActive:)
                name:UIApplicationWillResignActiveNotification
              object:nil];
     
     [self configUI];
}
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
     self.navigationController.navigationBar.hidden =  NO;
    [self startScan];
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];

}

- (void)setupNavigationBar {
     self.navigationController.navigationBar.translucent = YES;
     [self.navigationController.navigationBar setBackgroundImage:[UIImage createImageWithColor:[UIColor clearColor]] forBarMetrics:UIBarMetricsDefault];
     NSDictionary *textAttributes = @{
                                      NSFontAttributeName: [UIFont boldSystemFontOfSize:18],
                                      NSForegroundColorAttributeName:WhiteColor
                                      };
     [self.navigationController.navigationBar setTitleTextAttributes:textAttributes];
     
     self.navigationItem.title = @"掃碼";
     UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
     backButton.frame = CGRectMake(0, 0, 40, 40);
     [backButton setImage:[UIImage imageNamed:@"nav_back_w"] forState:UIControlStateNormal];
     [backButton addTarget:self action:@selector(scanBack) forControlEvents:UIControlEventTouchUpInside];
     backButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
     self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
     UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeCustom];
     rightButton.frame = CGRectMake(0, 0, 40, 40);
     [rightButton setTitle:@"相冊(cè)" forState:UIControlStateNormal];
     [rightButton setTitleColor:WhiteColor forState:UIControlStateNormal];
     rightButton.titleLabel.font = FontRegular(16);
     rightButton.alpha = 0.8;
     [rightButton addTarget:self action:@selector(rightBarButtonItenAction) forControlEvents:UIControlEventTouchUpInside];
     rightButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
     self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightButton];
}
-(void)configUI{
     [self setupNavigationBar];
    _isScaning = YES;
     [self.view.layer addSublayer:self.videoPreviewLayer];
     [self.view addSubview:self.titleLabel];
     [self.view addSubview:self.promptLabel];

    [self.view addSubview:self.myScanBGView];

    [self.view addSubview:self.lineView];

    [self scanLineStartAction];

}

- (void)scanLineStartAction{
    
    [self scanLineStopAction];
    
    CAAnimationGroup *group = [CAAnimationGroup animation];
    CABasicAnimation *scanAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
    scanAnimation.fromValue = @(80);
    scanAnimation.toValue = @(SCREEN_HEIGHT-160-95);
    scanAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    
    CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    opacityAnimation.fromValue = @(1);
    opacityAnimation.toValue = @(0);
    opacityAnimation.repeatCount = CGFLOAT_MAX;
    opacityAnimation.duration = 0.5;
    opacityAnimation.beginTime = 2;
    
    group.animations = @[scanAnimation,opacityAnimation];
    group.removedOnCompletion = NO;
    group.fillMode = kCAFillModeForwards;
    group.duration  = 2.5;
    group.repeatCount = CGFLOAT_MAX;
    
    [self.lineView.layer addAnimation:group forKey:@"basic"];
}
-(void)scanLineStopAction{
    
    [self.lineView.layer removeAllAnimations];
}

-(void)scanBack{
    if (self.navigationController) {
        [self.navigationController popViewControllerAnimated:YES];
    }
}

- (void)rightBarButtonItenAction {
    WeakSelf(ws);
     
     UIImagePickerController *picker = [UIImagePickerController new];
     picker.delegate = (id)self;
     picker.allowsEditing = NO;
     picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
     picker.modalPresentationStyle = UIModalPresentationFullScreen;
     [ws.navigationController presentViewController:picker animated:YES completion:nil];

}
-(void)dealloc {
    
    [self.videoPreviewLayer removeFromSuperlayer];
    self.videoPreviewLayer = nil;
    [self scanLineStopAction];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    NSLog(@"%s",__func__);
}
#pragma mark -----public

- (void)playSoundName:(NSString *)name {
    /// 靜態(tài)庫(kù) path 的獲取
    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:nil];
    if (!path) {
        /// 動(dòng)態(tài)庫(kù) path 的獲取
        path = [[NSBundle bundleForClass:[self class]] pathForResource:name ofType:nil];
    }
    NSURL *fileUrl = [NSURL fileURLWithPath:path];
    
    SystemSoundID soundID = 0;
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID);
    AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, NULL, NULL);
    AudioServicesPlaySystemSound(soundID);
}

- (void)startScan{
    _isScaning = YES;
    [self.videoPreviewLayer.session startRunning];
    [self scanLineStartAction];
}
- (void)stopScan{
    _isScaning = NO;
    [self.videoPreviewLayer.session stopRunning];
    [self scanLineStopAction];
}
-(void)openFlash:(UIButton*)button{
    button.selected = !button.selected;
    if (button.selected) {
        [self turnTorchOn:YES];
    }
    else{
        [self turnTorchOn:NO];
    }
}

- (void)turnTorchOn:(BOOL)on
{
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        
        if ([device hasTorch] && [device hasFlash]){
            [device lockForConfiguration:nil];
            if (on) {
                device.torchMode = AVCaptureTorchModeOn;
            } else {

                device.torchMode = AVCaptureTorchModeOff;
            }
            [device unlockForConfiguration];
        }
    }
}
#pragma mark -----Notification
- (void)applicationDidBecomeActive:(UIApplication *)application {
    [self startScan];
}

- (void)applicationWillResignActive:(UIApplication *)application {
    [self stopScan];
}

#pragma mark ------imagepickDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info
{
     WeakSelf(weakSelf);
     [picker dismissViewControllerAnimated:YES completion:^{
         [weakSelf handleImageInfo:info];
     }];
}



- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
    [picker dismissViewControllerAnimated:YES completion:nil];
    [self startScan];
}

+(UIViewController *)showSelectControllerWithImage:(UIImage *)image dataArray:(NSArray *)array block:(ScanResultBlock)block
{
    HDXYScanImageSelectController *controller = [HDXYScanImageSelectController new];
    controller.image =image;
    controller.tagArray = array;
    controller.scanBlock = block;
    return controller;
}


#pragma mark 圖片識(shí)別
- (void)handleImageInfo:(NSDictionary *)info{

     [self startScan];
     UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
     if (!image){
          image = [info objectForKey:UIImagePickerControllerOriginalImage];
     }
     __block NSString *resultStr = nil;
     __block BOOL haveCode = NO;
//圖片識(shí)別二維碼
     NSArray *features = [self.detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]];
//判斷是否識(shí)別出二維碼
     [features enumerateObjectsUsingBlock:^(CIQRCodeFeature *obj, NSUInteger idx, BOOL *stop) {
        if (obj.messageString.length > 0) {
             resultStr = obj.messageString;
             NSLog(@"%@",resultStr);
             haveCode = resultStr.length>0?YES:NO;
             *stop = YES;
          }
     }];
     [self stopScan];
     NSMutableArray *muchArray = [NSMutableArray new];
     if (haveCode) {
          [features enumerateObjectsUsingBlock:^(CIQRCodeFeature *obj, NSUInteger idx, BOOL *stop) {
               NSMutableDictionary *dic = [NSMutableDictionary new];
               CGRect frame =obj.bounds;
               NSString *frameStr = NSStringFromCGRect(frame);
               [dic setObject:frameStr forKey:@"frame"];
               NSString *code = obj.messageString;
               [dic setObject:code forKey:@"code"];
               [muchArray addObject:dic];
          }];
     }
     if (self.scanOutputs) {
          self.scanOutputs(muchArray);
          return;
     }
     WeakSelf(weakSelf);
     [self.navigationController pushViewController:[XYQRScanViewController showSelectControllerWithImage:image dataArray:muchArray block:^(NSString *result) {
          if (result && result.length>0) {
               if (weakSelf.scanBlock) {
                    [weakSelf.navigationController popViewControllerAnimated:NO];
                    weakSelf.scanBlock(result);
               }
          }
     }] animated:NO];
     return;
}
#pragma mark ------AVCaptureVideoDataOutputSampleBufferDelegate
//弱光識(shí)別
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
    
    static BOOL isStop = false;
    if (isStop) return;
    
    isStop = true;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //0.5秒一次弱光監(jiān)聽
        isStop = false;
    });
    
    CFDictionaryRef metadataDict = CMCopyDictionaryOfAttachments(NULL,sampleBuffer, kCMAttachmentMode_ShouldPropagate);
    NSDictionary *metadata = [[NSMutableDictionary alloc] initWithDictionary:(__bridge NSDictionary*)metadataDict];
    CFRelease(metadataDict);
    NSDictionary *exifMetadata = [[metadata objectForKey:(NSString *)kCGImagePropertyExifDictionary] mutableCopy];
    float brightnessValue = [[exifMetadata objectForKey:(NSString *)kCGImagePropertyExifBrightnessValue] floatValue];

    if (brightnessValue < 0 && !self.lightButton.selected && self.lightButton.isHidden) {
        self.lightButton.hidden = NO;
    }
    if (brightnessValue > 0 && !self.lightButton.selected && !self.lightButton.isHidden) {
        self.lightButton.hidden = YES;
    }
}

#pragma mark ------AVCaptureMetadataOutputObjectsDelegate讥蔽,掃描結(jié)果輸出流代理

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    //判斷是否有數(shù)據(jù),是否是二維碼數(shù)據(jù)
    NSMutableArray *muchArray = [NSMutableArray new];
    if (metadataObjects.count > 0) {
        [metadataObjects enumerateObjectsUsingBlock:^(AVMetadataMachineReadableCodeObject *obj, NSUInteger idx, BOOL *stop) {
            if ([obj.type isEqualToString:AVMetadataObjectTypeQRCode]) {
                [muchArray addObject:obj];
            }
        }];
        if (muchArray.count>0) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self analyseResultAry:muchArray];
            });
        }
    }

}
- (void)analyseResultAry:(NSArray *)resultArray{
     if (!_isScaning) {
          return;
     }
     [self stopScan];
     [self playSoundName:@"SGQRCode.bundle/sound.caf"];
     NSMutableArray *muchArray = [NSMutableArray new];
     [resultArray enumerateObjectsUsingBlock:^(AVMetadataMachineReadableCodeObject *result, NSUInteger idx, BOOL *stop) {
          NSMutableDictionary *dic = [NSMutableDictionary new];
          NSString *code = result.stringValue;
          [dic setObject:code forKey:@"code"];
        
          CGRect frame = [self makeFrameWithCodeObject: result];
          NSString *frameStr = NSStringFromCGRect(frame);
          [dic setObject:frameStr forKey:@"frame"];
          [muchArray addObject:dic];
     }];
     
     if (muchArray.count>=1) {
          UIImage *image;
          WeakSelf(weakSelf);
          if (self.scanOutputs) {
               self.scanOutputs(muchArray);
               return;
          }

          UIViewController *viewController = [XYQRScanViewController showSelectControllerWithImage:image dataArray:muchArray block:^(NSString *result) {
               weakSelf.popButton.hidden = NO;
               weakSelf.lineView.hidden = NO;
               if (weakSelf.scanBlock) {
                    if (result) {
                         [weakSelf.navigationController popViewControllerAnimated:YES];
                         weakSelf.scanBlock(result);
                    }else{
                         [weakSelf startScan];
                    }
               }
          }];
          viewController.modalPresentationStyle =UIModalPresentationOverFullScreen;
          [self.navigationController presentViewController:viewController animated:NO completion:nil];
          self.popButton.hidden = YES;
          self.lineView.hidden = YES;
          return;
     }
     [self startScan];
}

/*
 AVMetadataMachineReadableCodeObject人乓,輸出的點(diǎn)位坐標(biāo)是其在原始數(shù)據(jù)流上的坐標(biāo)勤篮,與屏幕視圖坐標(biāo)不一樣,(坐標(biāo)系色罚,值都會(huì)有差別)
     將坐標(biāo)值轉(zhuǎn)為屏幕顯示的圖像視圖(self.videoPreviewLayer)上的坐標(biāo)值
 */
-(CGRect)makeFrameWithCodeObject:(AVMetadataMachineReadableCodeObject *)objc
{
     //將二維碼坐標(biāo)轉(zhuǎn)化為掃碼控件輸出視圖上的坐標(biāo)
     CGSize isize = CGSizeMake(720.0, 1280.0); // 尺寸可以考慮不要寫死,當(dāng)前設(shè)置的是captureSession.sessionPreset = AVCaptureSessionPreset1280x720;
//     CGSize isize = self.view.frame.size; //掃碼控件的輸出尺寸,
     float Wout = 0.00;
     float Hout = 0.00;
     BOOL wMore = YES;
    /*取分辨率與輸出的layer尺寸差账劲,
     此處以AVLayerVideoGravityResizeAspectFill填充方式為例戳护,判斷掃描的范圍更寬還是更長(zhǎng),并計(jì)算出超出部分的尺寸瀑焦,后續(xù)計(jì)算減去這部分腌且。
     如果是其它填充方式,計(jì)算方式不一樣(比如AVLayerVideoGravityResizeAspect榛瓮,則計(jì)算計(jì)算留白的尺寸铺董,并后續(xù)補(bǔ)足這部分)
     */
     if (isize.width/isize.height > self.videoPreviewLayer.bounds.size.width/self.videoPreviewLayer.bounds.size.height) {
          //當(dāng)更寬時(shí),計(jì)算掃描的坐標(biāo)x為0 的點(diǎn)比輸出視圖的0點(diǎn)差多少(輸出視圖為全屏?xí)r,即屏幕外有多少)
          wMore = YES;
          Wout = (isize.width/isize.height)* self.videoPreviewLayer.bounds.size.height;
          Wout = Wout - self.videoPreviewLayer.bounds.size.width;
          Wout = Wout/2;
     }else{
          // 當(dāng)更長(zhǎng)時(shí)精续,計(jì)算y軸超出多少坝锰。
          wMore = NO;
          Hout = (isize.height/isize.width)* self.videoPreviewLayer.bounds.size.width;
          Hout = Hout  - self.videoPreviewLayer.bounds.size.height;
          Hout = Hout/2;
     }
    
     CGPoint point1 = CGPointZero;
     CGPoint point2 = CGPointZero;
     CGPoint point3 = CGPointZero;
     CGPoint point4 = CGPointZero;
     /*
      源坐標(biāo)系下frame和角點(diǎn),都是比例值重付,即源視頻流尺寸下的百分比值顷级。
      例子:frame :(x = 0.26720550656318665, y = 0.0014114481164142489), size = (width = 0.16406852006912231, height = 0.29584407806396484))
      objc.corners:{0.26823519751360592, 0.29203594744002659}
                    {0.4312740177700658, 0.29725551905635411}
                    {0.4294213439632073, 0.012761536345436197}
                    {0.26720551457151021, 0.0014114481640513654}
      */
     CGRect frame = objc.bounds;//在源坐標(biāo)系的frame,
     NSArray *array = objc.corners;//源坐標(biāo)系下二維碼的角點(diǎn)
     CGPoint P = frame.origin;
     CGSize S = frame.size;
     
     //獲取點(diǎn)
     for (int n = 0; n< array.count; n++) {
          
          CGPoint point = CGPointZero;
          CFDictionaryRef dict = (__bridge CFDictionaryRef)(array[n]);
          CGPointMakeWithDictionaryRepresentation(dict, &point);
          NSLog(@"二維碼角點(diǎn)%@",NSStringFromCGPoint(point));
          //交換xy軸
          point.x = point.y +  point.x;
          point.y = point.x - point.y;
          point.x = point.x - point.y;
          //x軸反轉(zhuǎn)
          point.x = (1-point.x);
          //point乘以比列确垫。減去尺寸差弓颈,
          if (wMore) {
               point.x = (point.x * (isize.width/isize.height)* self.videoPreviewLayer.bounds.size.height) - Wout;
               point.y = self.videoPreviewLayer.bounds.size.height *(point.y);
          }else{
               point.x = self.videoPreviewLayer.bounds.size.width *(point.x);
               point.y = (point.y) * (isize.height/isize.width)* self.videoPreviewLayer.bounds.size.width - Hout;
          }
          if (n == 0) {
               point1 = point;
          }
          if (n == 1) {
               point2 = point;
          }
          if (n == 2) {
               point3 = point;
          }
          if (n == 3) {
               point4 = point;
          }
     }
     //通過獲取最小和最大的X,Y值删掀,二維碼在視圖上的frame(前面得到的點(diǎn)不一定是正方形的二維碼翔冀,也可能是菱形的或者有一定旋轉(zhuǎn)角度的)
     float minX = point1.x;
     minX = minX>point2.x?point2.x:minX;
     minX = minX>point3.x?point3.x:minX;
     minX = minX>point4.x?point4.x:minX;
        
     float minY = point1.y;
     minY = minY>point2.y?point2.y:minY;
     minY = minY>point3.y?point3.y:minY;
     minY = minY>point4.y?point4.y:minY;
     P.x = minX;
     P.y = minY;
        
     float maxX = point1.x;
     maxX = maxX<point2.x?point2.x:maxX;
     maxX = maxX<point3.x?point3.x:maxX;
     maxX = maxX<point4.x?point4.x:maxX;
        
     float maxY = point1.y;
     maxY = maxY<point2.y?point2.y:maxY;
     maxY = maxY<point3.y?point3.y:maxY;
     maxY = maxY<point4.y?point4.y:maxY;
        
     S.width = maxX - minX;
     S.height = maxY - minY;

     //y軸坐標(biāo)方向調(diào)整
     CGRect QRFrame = CGRectMake(P.x , P.y  , S.width, S.width);
     return QRFrame;
}

#pragma mark 懶加載

- (UILabel *)titleLabel {
    if (!_titleLabel) {
        _titleLabel = [[UILabel alloc] init];
        _titleLabel.backgroundColor = [UIColor clearColor];
        CGFloat promptLabelX = 0;
        CGFloat promptLabelY = 0.12 * SCREEN_HEIGHT;
        CGFloat promptLabelW = SCREEN_WIDTH;
        CGFloat promptLabelH = 25;
        _titleLabel.frame = CGRectMake(promptLabelX, promptLabelY, promptLabelW, promptLabelH);
        _titleLabel.textAlignment = NSTextAlignmentCenter;
        _titleLabel.font = FontRegular(16);
        _titleLabel.textColor = WhiteColor;
        _titleLabel.alpha = 0.8;
        _titleLabel.text = @"掃描二維碼";
    }
    return _titleLabel;
}

- (UIView *)bottomView {
    if (!_bottomView) {
        _bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT - 0)];
        _bottomView.backgroundColor = [BlackColor colorWithAlphaComponent:0.6];
    }
    return _bottomView;
}

-(UIImageView *)lineView{
    
    if (!_lineView){
         /// 靜態(tài)庫(kù) url 的獲取, 掃描線暫時(shí)用的原第三方庫(kù)的圖片,
         NSURL *url = [[NSBundle mainBundle] URLForResource:@"SGQRCode" withExtension:@"bundle"];
         if (!url) {
             /// 動(dòng)態(tài)庫(kù) url 的獲取
             url = [[NSBundle bundleForClass:[self class]] URLForResource:@"SGQRCode" withExtension:@"bundle"];
         }
         NSBundle *bundle = [NSBundle bundleWithURL:url];
         
         UIImage *image = [UIImage imageNamed:@"QRCodeScanLine" inBundle:bundle compatibleWithTraitCollection:nil];
         if (!image) {
             image = [UIImage imageNamed:@"QRCodeScanLine"];
         }

//        UIImage *lineImage = [UIImage imageNamed:@"QRCodeScanLine@2x.png"];
        CGFloat lineHeight = 30;
        CGFloat lineWidth = CGRectGetWidth(self.view.frame);
        _lineView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 40, lineWidth, lineHeight)];
        _lineView.contentMode = UIViewContentModeScaleToFill;

        _lineView.image = image;

    }
    return _lineView;
}

-(AVCaptureVideoPreviewLayer *)videoPreviewLayer{
     
     if (!_videoPreviewLayer) {
         NSError *error;
         AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; //相機(jī)的硬件接口
         AVCaptureDeviceInput *input    = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];  // 用于流的捕獲,輸入流
         if (!input) {
              NSLog(@"%@", error.localizedDescription);
              [self.navigationController popViewControllerAnimated:YES];
              return nil;
         }else{
              //設(shè)置視頻會(huì)話(時(shí)域)流
              AVCaptureSession *captureSession = [AVCaptureSession new];
              [captureSession addInput:input]; //設(shè)置輸入流
              captureSession.sessionPreset = AVCaptureSessionPreset1280x720; //輸出的分辨率
              //創(chuàng)建流輸出
              AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
              [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatch_queue_create("ease_capture_queue",NULL)];//設(shè)置輸出代理披泪,及處理線程(輸出類型為上面設(shè)置的類型纤子,比如二維碼或人臉數(shù)據(jù)或者別的等等)
              [captureSession addOutput:captureMetadataOutput];//添加流輸出到session
              //設(shè)置輸出類型:AVMetadataObjectTypeQRCode,//其它功能比如人臉掃描等可以自行研究
              if (![captureMetadataOutput.availableMetadataObjectTypes containsObject:AVMetadataObjectTypeQRCode]) {
                   NSLog(NSLocalizedString(@"攝像頭不支持掃描二維碼付呕!", nil));
                   [self.navigationController popViewControllerAnimated:YES];
              }else{
                   [captureMetadataOutput setMetadataObjectTypes:captureMetadataOutput.availableMetadataObjectTypes];
              }
              
              
            
              captureMetadataOutput.rectOfInterest = CGRectMake(0,0,1,1);//設(shè)置掃描區(qū)域计福。。默認(rèn)是手機(jī)頭向左的橫屏坐標(biāo)系(逆時(shí)針旋轉(zhuǎn)90度)徽职,左上角為(0象颖,0)點(diǎn).坐標(biāo)系↓→
              // 弱光識(shí)別監(jiān)聽
              AVCaptureVideoDataOutput *buffer = [[AVCaptureVideoDataOutput alloc] init];
              [buffer setSampleBufferDelegate:self queue:dispatch_get_main_queue()];

              if ([captureSession canAddOutput:buffer]){
                   [captureSession addOutput:buffer];
              }
              //將捕獲的數(shù)據(jù)流展現(xiàn)出來
              _videoPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
              [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; //等比例填充,超出部分會(huì)被剪裁(這也就是為什么有些掃碼屏幕內(nèi)只顯示了一半也能完成掃描姆钉。其實(shí)攝像頭已經(jīng)捕獲了)(AVLayerVideoGravityResizeAspect全部顯示说订,少的部分有留白)
              [_videoPreviewLayer setFrame:self.view.bounds];
              
              
//              //以下是修改掃描區(qū)域?yàn)槠聊粌?nèi)的方案,修改參數(shù)可以指定范圍內(nèi)掃描
//              CGSize isize = CGSizeMake(720.0, 1280.0); //當(dāng)前設(shè)置的是captureSession.sessionPreset = AVCaptureSessionPreset1280x720;
//              float Wout = 0.00;
//              float Hout = 0.00;
//              BOOL wMore = YES;
//             //取分辨率與輸出的layer尺寸差潮瓶,首先判斷目掃描的范圍更寬還是更長(zhǎng)陶冷,
//              if (isize.width/isize.height > self.view.bounds.size.width/self.view.bounds.size.height) {
//                   //當(dāng)更寬時(shí),計(jì)算掃描的坐標(biāo)x為0 的點(diǎn)比輸出視圖的0點(diǎn)差多少(輸出視圖為全屏?xí)r毯辅,即屏幕外有多少)
//                   wMore = YES;
//                   Wout = (isize.width/isize.height)* self.videoPreviewLayer.bounds.size.height;
//                   Wout = Wout - self.videoPreviewLayer.bounds.size.width;
//                   Wout = Wout/2;
//              }else{
//                   // 當(dāng)更長(zhǎng)時(shí)埂伦,計(jì)算y軸超出多少。
//                   wMore = NO;
//                   Hout = (isize.height/isize.width)* self.videoPreviewLayer.bounds.size.width;
//                   Hout = Hout  - self.videoPreviewLayer.bounds.size.height;
//                   Hout = Hout/2;
//              }
//              if (wMore) {
//                   captureMetadataOutput.rectOfInterest = CGRectMake(0,Wout/720.0,1,(720.0-2*Wout)/720.0);
//              }else{
//                   captureMetadataOutput.rectOfInterest = CGRectMake(Hout/1280.0,0,(1280.0-2*Hout)/1280.0,0);
//              }
//              captureMetadataOutput.rectOfInterest = CGRectMake(0,0,0.5,0.5);
         }
     }
     return _videoPreviewLayer;
}

@end

展示點(diǎn)選按鈕

.h:

#import <UIKit/UIKit.h>

@interface HDXYScanImageSelectController : UIViewController
@property (nonatomic, copy) void(^scanBlock)(NSString *scanStr);//掃碼點(diǎn)選回調(diào)
/*
 選擇圖片掃碼結(jié)果展示:傳入image思恐。
 攝像頭掃碼結(jié)果展示:image不需要傳入沾谜,后面會(huì)自動(dòng)生成透明圖片尺寸與掃碼頁面視頻流的展示大小一致,如果掃碼頁面視頻流不是全圖則需要修改這部分邏輯
 */
@property(nonatomic,copy)UIImage *image;
@property(nonatomic,copy)NSArray *tagArray;

@end

.m:


#import "HDXYScanImageSelectController.h"

#define maxBtnSize 54
#define minBtnSize 18

#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
#define kDevice_Is_iPhoneX (SCREEN_WIDTH >= 375.f && SCREEN_HEIGHT >= 812.f)
#define kSafeArea_Top (kDevice_Is_iPhoneX? 44: 20 )
#define kSafeArea_Bottom ((kDevice_Is_iPhoneX? 34: 0))

@interface HDXYScanImageSelectController ()
@property (nonatomic,strong)UIButton *popButton;
@property (nonatomic,strong)UILabel *downLable;
@property (nonatomic,strong)UIView *bigDarkView;
@property BOOL noImage;
@end

@implementation HDXYScanImageSelectController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.view addSubview:self.popButton];
    [self.popButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).offset(25);
        make.top.equalTo(self.view).offset(12.5+(kDevice_Is_iPhoneX?44:20));
    }];
    // Do any additional setup after loading the view.
}

-(void)viewWillAppear:(BOOL)animated
{
    self.view.backgroundColor = [UIColor blackColor];
    self.navigationController.navigationBar.hidden =  YES;
    self.noImage = NO;
    if (!self.image) {
        self.noImage = YES;
        self.image = [self createImageWithColor:[UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:0.5]];
        self.view.backgroundColor = [UIColor clearColor];
    }

    UIImageView *imageView = [self buildImageView];
    
    [self.view addSubview:imageView];
    if (self.tagArray && self.tagArray.count>0) {
        [self.tagArray enumerateObjectsUsingBlock:^(NSDictionary *dataDic, NSUInteger idx, BOOL *stop) {
            UIButton *btn = [self buildBtnWithDic:dataDic andNumber:idx];
            [imageView addSubview:btn];
        }];

        [self.view addSubview:self.downLable];
        [self.downLable mas_makeConstraints:^(MASConstraintMaker *make) {
                make.centerX.mas_equalTo(self.view.mas_centerX);
                make.bottom.mas_offset(-40-kSafeArea_Bottom);
        }];
        [self.view bringSubviewToFront:self.popButton];
    }else{
        [self.view addSubview:self.bigDarkView];
        [self.bigDarkView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.right.top.bottom.mas_equalTo(self.view);
        }];
    }
    [self.view bringSubviewToFront:self.popButton];
    [super viewWillAppear:animated];
}
-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
   //只有一個(gè)二維碼時(shí)胀莹,展示一下就自動(dòng)選擇
    if (self.tagArray.count == 1) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSDictionary *dataDic = self.tagArray[0];
            [self doingWithMessage:dataDic[@"code"]];
        });
    }
}


-(UIButton *)buildBtnWithDic:(NSDictionary *)dic andNumber:(NSInteger)number
{
     CGSize startImageSize = [HDXYScanImageSelectController getSizeWithImage:self.image];
     CGFloat fixelW = startImageSize.width;
     CGFloat fixelH = startImageSize.height;
    //計(jì)算UIimageView的尺寸基跑,
     if (fixelH/fixelW > self.view.bounds.size.height/self.view.bounds.size.width) {
          fixelW = (fixelW/fixelH) * self.view.bounds.size.height;
          fixelH = self.view.bounds.size.height;
     }else{
          fixelH = (fixelH/fixelW) * self.view.bounds.size.width;
          fixelW = self.view.bounds.size.width;
     }
     float scale =  fixelW/startImageSize.width;
     CGRect btnFrame =  CGRectFromString(dic[@"frame"]);
     //根據(jù)圖片方向調(diào)整frame
     if (!self.noImage) {
          btnFrame = [HDXYScanImageSelectController exChangeFrame:btnFrame withImage:self.image];
     }
     //坐標(biāo)等比縮放
     btnFrame = CGRectMake(btnFrame.origin.x*scale, btnFrame.origin.y *scale, btnFrame.size.width *scale, btnFrame.size.height *scale);

    //按鈕初步大小調(diào)整
    btnFrame = CGRectMake(btnFrame.origin.x + btnFrame.size.width/4,btnFrame.origin.y + btnFrame.size.height/4, btnFrame.size.width/2, btnFrame.size.height/2);
    if (btnFrame.size.width != btnFrame.size.height) {
        float w = btnFrame.size.width;
        float h = btnFrame.size.height;
        btnFrame = CGRectMake(btnFrame.origin.x, btnFrame.origin.y + (h-w)/2, w, w);
    }
    if (btnFrame.size.width > maxBtnSize) {
        float w = btnFrame.size.width;
        float h = btnFrame.size.height;
        btnFrame = CGRectMake(btnFrame.origin.x + (w-maxBtnSize)/2, btnFrame.origin.y + (h-maxBtnSize)/2, maxBtnSize, maxBtnSize);
    }
    if (btnFrame.size.width < minBtnSize) {
        float w = btnFrame.size.width;
        float h = btnFrame.size.height;
        btnFrame = CGRectMake(btnFrame.origin.x + (w-minBtnSize)/2, btnFrame.origin.y + (h-minBtnSize)/2, minBtnSize, minBtnSize);
    }
    btnFrame.size.width = btnFrame.size.height;
    UIButton *btn = [[UIButton alloc]init];
    btn.frame = btnFrame;

    [btn setBackgroundImage:[UIImage imageNamed:@"scanMany"] forState:UIControlStateNormal];
     btn.backgroundColor = [UIColor yellowColor];
    btn.alpha = 0.99;
    btn.tag = number;
    btn.clipsToBounds = YES;
    [btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    [btn.layer addAnimation:[self opacityForever_Animation:0.7] forKey:nil];
    return btn;
}


-(void)clickBtn:(UIButton *)btn
{
    NSInteger number = btn.tag;
    NSString *messageStr = self.tagArray[number][@"code"];
    [self doingWithMessage:messageStr];
    
}

-(void)clickBigBackView:(id)sender
{
    [self doingWithMessage:nil];
}
-(void)doingWithMessage:(NSString *)msg
{
    if (self.navigationController) {
        [self.navigationController popViewControllerAnimated:YES];
        if (self.scanBlock) {
            self.scanBlock(msg);
        }
    }else{
        [self dismissViewControllerAnimated:NO completion:^{
            if (self.scanBlock) {
                self.scanBlock(msg);
            }
        }];
    }
}

#pragma mark === 永久閃爍的動(dòng)畫 ======
-(CABasicAnimation *)opacityForever_Animation:(float)time
{
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.fromValue = [NSNumber numberWithFloat:0.99f];
    animation.toValue = [NSNumber numberWithFloat:0.3f];
    animation.autoreverses = YES;
    animation.duration = time;
    animation.repeatCount = MAXFLOAT;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];///沒有的話是均勻的動(dòng)畫。
    return animation;
}


+(CGSize)getSizeWithImage:(UIImage *)image
{
    CGFloat fixelW;
    CGFloat fixelH;
    fixelW = CGImageGetWidth(image.CGImage);
    fixelH = CGImageGetHeight(image.CGImage);
    if (image.imageOrientation == UIImageOrientationLeft ||
        image.imageOrientation == UIImageOrientationRight ||
        image.imageOrientation == UIImageOrientationLeftMirrored ||
        image.imageOrientation == UIImageOrientationRightMirrored) {
        
        fixelW = CGImageGetHeight(image.CGImage);
        fixelH = CGImageGetWidth(image.CGImage);
    }
    
    return CGSizeMake(fixelW, fixelH);
}
//根據(jù)圖片方向調(diào)整二維碼坐標(biāo),圖片方向根據(jù)拍攝時(shí)手機(jī)方向而不同
+(CGRect)exChangeFrame:(CGRect)frame withImage:(UIImage *)image
{
     CGFloat fixelW = CGImageGetWidth(image.CGImage);
     CGFloat fixelH = CGImageGetHeight(image.CGImage);
     CGFloat x = frame.origin.x;
     CGFloat y = frame.origin.y;
     CGFloat w = frame.size.width;
     CGFloat h = frame.size.height;
     if (image.imageOrientation == UIImageOrientationUp){
          frame.origin.y = fixelH-y-h;
     }else if (image.imageOrientation == UIImageOrientationLeft){
          //方向逆時(shí)針旋轉(zhuǎn)90°拍攝,已實(shí)現(xiàn)
          frame.origin.x = fixelH-y-h;
          frame.origin.y = fixelW-x-w;
     }else if (image.imageOrientation == UIImageOrientationRight){
          //順時(shí)針旋轉(zhuǎn)90度拍攝描焰,已實(shí)現(xiàn)
          frame.origin.x = y;
          frame.origin.y = x;
     }else if (image.imageOrientation == UIImageOrientationDown){
          //旋轉(zhuǎn)180度拍攝的
          frame.origin.x = fixelW-x-w;
          frame.origin.y = y;
     }else if (image.imageOrientation == UIImageOrientationUpMirrored){
          //左右鏡像媳否,已實(shí)現(xiàn)未驗(yàn)證
          frame.origin.x = fixelW -x-w;
          frame.origin.y = fixelH-y-h;
        
     }else if (image.imageOrientation == UIImageOrientationDownMirrored){
          //翻轉(zhuǎn)180度后鏡像,已實(shí)現(xiàn)未驗(yàn)證
          frame.origin.y = y;
          frame.origin.x = x;
     }else if (image.imageOrientation == UIImageOrientationRightMirrored){
          //表示圖片被順時(shí)針翻轉(zhuǎn)90°后的鏡面圖像,已實(shí)現(xiàn)未驗(yàn)證
          frame.origin.x = fixelH -y-h;
          frame.origin.y = x;
     }else if (image.imageOrientation == UIImageOrientationLeftMirrored){
          //坐標(biāo)系逆時(shí)針旋轉(zhuǎn)90°并鏡像,已實(shí)現(xiàn)未驗(yàn)證
          frame.origin.x = y;
          frame.origin.y = fixelW-x-w;
     }
     return frame;
}
-(UIImageView *)buildImageView
{
    CGFloat fixelW = [HDXYScanImageSelectController getSizeWithImage:self.image].width;
    CGFloat fixelH = [HDXYScanImageSelectController getSizeWithImage:self.image].height;
    if (fixelH/fixelW > self.view.bounds.size.height/self.view.bounds.size.width) {
        fixelW = (fixelW/fixelH) * self.view.bounds.size.height;
        fixelH = self.view.bounds.size.height;
    }else{
        fixelH = (fixelH/fixelW) * self.view.bounds.size.width;
        fixelW = self.view.bounds.size.width;
    }
    UIImageView *imageView = [[UIImageView alloc]initWithImage:self.image];
    imageView.bounds = CGRectMake(0, 0, fixelW, fixelH);
    imageView.center = self.view.center;
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.userInteractionEnabled = YES;
    return imageView;
}
-(UIButton *)popButton{
    if (!_popButton) {
        _popButton = [[UIButton alloc]init];
//        [_popButton setImage:[UIImage imageNamed:@"scan_closed_icon"] forState:UIControlStateNormal];
        [_popButton setTitle:@"取消" forState:UIControlStateNormal];
         [_popButton addTarget:self action:@selector(clickBigBackView:) forControlEvents:UIControlEventTouchUpInside];

    }
    return _popButton;
}
-(UILabel *)downLable
{
    if (!_downLable) {
        _downLable = [UILabel new];
        _downLable.text = @"輕觸小藍(lán)點(diǎn)篱竭,打開頁面";
        [_downLable setTextColor:[UIColor whiteColor]];
        [_downLable setBackgroundColor:[UIColor clearColor]];
        _downLable.textAlignment = NSTextAlignmentCenter;
    }
    return _downLable;
}
//顏色生成image
-(UIImage*) createImageWithColor:(UIColor*) color
{

    CGRect rect=CGRectMake(0.0f, 0.0f, SCREEN_WIDTH, SCREEN_HEIGHT);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return theImage;
}
-(UIView *)bigDarkView
{
     if (!_bigDarkView) {
          _bigDarkView = [UIView new];
          _bigDarkView.backgroundColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:0.5];
          UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickBigBackView:)];
          [tapGesture setNumberOfTapsRequired:1];
          [_bigDarkView addGestureRecognizer:tapGesture];
          UILabel *oneLabel = [UILabel new];
          oneLabel.text = @"未發(fā)現(xiàn)二維碼";
          oneLabel.textColor = [UIColor whiteColor];
          oneLabel.font = [UIFont fontWithName:@"FontWeightStyleRegular" size:17.0];
          oneLabel.textAlignment = NSTextAlignmentCenter;
          [_bigDarkView addSubview:oneLabel];
          [oneLabel mas_makeConstraints:^(MASConstraintMaker *make) {
               make.left.right.mas_equalTo(_bigDarkView);
               make.height.mas_offset(20);
               make.centerY.mas_equalTo(_bigDarkView.mas_centerY).mas_offset(-20);
          }];
          UILabel *twoLabel = [UILabel new];
          twoLabel.text = @"輕觸屏幕繼續(xù)掃描";
          twoLabel.textColor = [UIColor whiteColor];
          twoLabel.font = [UIFont fontWithName:@"FontWeightStyleRegular" size:14.0];;
          twoLabel.textAlignment = NSTextAlignmentCenter;
          [_bigDarkView addSubview:twoLabel];
          [twoLabel mas_makeConstraints:^(MASConstraintMaker *make) {
               make.left.right.mas_equalTo(_bigDarkView);
               make.height.mas_offset(20);
               make.centerY.mas_equalTo(_bigDarkView.mas_centerY);
          }];
     }
     return _bigDarkView;
}
@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末力图,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子室抽,更是在濱河造成了極大的恐慌搪哪,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坪圾,死亡現(xiàn)場(chǎng)離奇詭異晓折,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)兽泄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門漓概,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人病梢,你說我怎么就攤上這事胃珍。” “怎么了蜓陌?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵觅彰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我钮热,道長(zhǎng)填抬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任隧期,我火速辦了婚禮飒责,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仆潮。我一直安慰自己宏蛉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布性置。 她就那樣靜靜地躺著拾并,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹏浅。 梳的紋絲不亂的頭發(fā)上辟灰,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音篡石,去河邊找鬼。 笑死西采,一個(gè)胖子當(dāng)著我的面吹牛凰萨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼胖眷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼武通!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起珊搀,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤冶忱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后境析,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體囚枪,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年劳淆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了链沼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沛鸵,死狀恐怖括勺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情曲掰,我是刑警寧澤疾捍,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站栏妖,受9級(jí)特大地震影響乱豆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜底哥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一咙鞍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧趾徽,春花似錦续滋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至了袁,卻和暖如春朗恳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背载绿。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工粥诫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人崭庸。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓怀浆,卻偏偏與公主長(zhǎng)得像谊囚,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子执赡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容