原生二維碼掃描

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];//設(shè)備鎖
                [device setTorchMode:AVCaptureTorchModeOn];//手電筒打開
                [device unlockForConfiguration];//不需要自動(dòng)調(diào)用
            }
        
    }
}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 -- 是否有其他攝像設(shè)備 --
-(BOOL)hasMultipleCameras {
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
if (devices != nil && [devices count] > 1) {
    return YES;
}else{
    return NO;
}
}
//FIXME:MARK -- 設(shè)備方向 --
-(AVCaptureDevice *)cameraWithPositon:(AVCaptureDevicePosition )position {

NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *device in devices ) {
    if (device.position == position) {
        return device;
    }
}
    return nil;
}
//FIXME:MARK -- 設(shè)置攝像頭方向--
-(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){
            //前置狀態(tài)閃光等自動(dòng)關(guān)閉
            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;

//相機(jī)授權(quán)
[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];

//呈現(xiàn)圖片的一個(gè)圖層
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         授權(quán)請求
 *  @param  AVAuthorizationStatusDenied             授權(quán)失敗
 *  @param  AVAuthorizationStatusAuthorized         授權(quán)成功
 */

-(void)checkAVAuthorizationStatus{

AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status == AVAuthorizationStatusRestricted) {
    //客戶端未授權(quán)
    
}else if (status == AVAuthorizationStatusDenied){
    //用戶明確拒絕訪問
    UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"請?jiān)谠O(shè)置中開啟照相機(jī)權(quán)限" 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){
    //授權(quán)
}
}
-(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) {
    //獲取攝像設(shè)備
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    //創(chuàng)建輸入流
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
    if (!input) {
        return  nil;
    }
    //創(chuàng)建輸出流
    AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc]init];
    //設(shè)置代理或粮,在主線程里刷新
    [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    //設(shè)置掃描區(qū)域的比例
    CGFloat width = 300/CGRectGetWidth(self.view.bounds);
    CGFloat height = 300/CGRectGetHeight(self.view.bounds);
    //此屬性的值是一個(gè)CGRect指定一個(gè)rectofinterest可能提高某些類型的元數(shù)據(jù)的檢測性能围辙。此屬性的默認(rèn)值是價(jià)值cgrectmake(0肚豺,0,1,1)茫孔。元數(shù)據(jù)對(duì)象的邊界不與rectofinterest相交將不會(huì)返回
#warning rectOfInterest --> (y,x,height,width)且默認(rèn)(0,0,1,1)

    output.rectOfInterest = CGRectMake((1-height)/2, (1-width)/2, height, width);
    
    self.session = [[AVCaptureSession alloc]init];
    //高質(zhì)量采集率
    [self.session setSessionPreset:AVCaptureSessionPresetHigh];
    [self.session addInput:input];
    [self.session addOutput:output];
    
    //設(shè)置掃碼支持的編碼格式(條形碼和二維碼兼容)
    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 * 掃描結(jié)果事件
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"掃碼結(jié)果" 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.滾動(dòng)線的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;//采集信息區(qū)域的大小
CGFloat pickingFieldHieght = 300;

//創(chuàng)建上下文
CGContextRef contectRef = UIGraphicsGetCurrentContext();
//將當(dāng)前圖形狀態(tài)推入堆棧隘蝎,之后,您對(duì)圖形狀態(tài)所做的修改會(huì)影響隨后的描畫操作睁宰,但不影響存儲(chǔ)在堆棧中的拷貝
CGContextSaveGState(contectRef);
//設(shè)置填充顏色
CGContextSetRGBFillColor(contectRef, 0, 0, 0, 0.35);
//線的寬度
CGContextSetLineWidth(contectRef, 3);

CGRect pickingFieldRect = CGRectMake((width-pickingFieldWidth)/2, (height-pickingFieldWidth)/2, pickingFieldWidth, pickingFieldHieght);
//根據(jù)一個(gè)矩形劃線
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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肪获,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子柒傻,更是在濱河造成了極大的恐慌孝赫,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件红符,死亡現(xiàn)場離奇詭異青柄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)预侯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門刹前,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雌桑,你說我怎么就攤上這事喇喉。” “怎么了校坑?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵拣技,是天一觀的道長。 經(jīng)常有香客問我耍目,道長膏斤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任邪驮,我火速辦了婚禮莫辨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘毅访。我一直安慰自己沮榜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布喻粹。 她就那樣靜靜地躺著蟆融,像睡著了一般。 火紅的嫁衣襯著肌膚如雪守呜。 梳的紋絲不亂的頭發(fā)上型酥,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天山憨,我揣著相機(jī)與錄音,去河邊找鬼弥喉。 笑死郁竟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的由境。 我是一名探鬼主播枪孩,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼藻肄!你這毒婦竟也來了蔑舞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤嘹屯,失蹤者是張志新(化名)和其女友劉穎攻询,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體州弟,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钧栖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婆翔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拯杠。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖啃奴,靈堂內(nèi)的尸體忽然破棺而出潭陪,到底是詐尸還是另有隱情,我是刑警寧澤最蕾,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布依溯,位于F島的核電站,受9級(jí)特大地震影響瘟则,放射性物質(zhì)發(fā)生泄漏黎炉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一醋拧、第九天 我趴在偏房一處隱蔽的房頂上張望慷嗜。 院中可真熱鬧,春花似錦丹壕、人聲如沸庆械。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽干奢。三九已至,卻和暖如春盏袄,著一層夾襖步出監(jiān)牢的瞬間忿峻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工辕羽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逛尚,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓刁愿,卻偏偏與公主長得像绰寞,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铣口,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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