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