iOS功能 - 扫描二维码、条形码

扫描二维码 | 条形码

1 - 准备工作

① 配置 Info.plist  文件(相机权限)

<key>NSCameraUsageDescription</key>
<string>App需您的同意才能访问相机</string>

② 使用到的扩展:充当遮罩层

// - UIImage+mask.h

复制代码
 1 #import <UIKit/UIKit.h>
 2 @interface UIImage (mask)
 3 /**
 4  *  @param  maskRect    遮罩层的 Rect
 5  *  @param  clearRect  镂空的 Rect
 6  *
 7  *  @return 遮罩层图片
 8  */
 9 + (UIImage *)maskImageWithMaskRect:(CGRect)maskRect clearRect:(CGRect)clearRect;
10 
11 @end
复制代码

// - UIImage+mask.m

复制代码
 1 #import "UIImage+mask.h"
 2 @implementation UIImage (mask)
 3 
 4 + (UIImage *)maskImageWithMaskRect:(CGRect)maskRect clearRect:(CGRect)clearRect{
 5     
 6     UIGraphicsBeginImageContext(maskRect.size);
 7     CGContextRef ctx = UIGraphicsGetCurrentContext();
 8     CGContextSetRGBFillColor(ctx, 0,0,0,0.6);
 9     CGRect drawRect =maskRect;
10 
11     CGContextFillRect(ctx, drawRect);
12 
13     drawRect = clearRect;
14     CGContextClearRect(ctx, drawRect);
15 
16     UIImage* returnimage = UIGraphicsGetImageFromCurrentImageContext();
17     UIGraphicsEndImageContext();
18     return returnimage;
19 }
20 
21 @end
复制代码

2 - 代码示例:实现二维码扫描、手电筒功开关功能

// - ScanQRcodeVC.h:扫码页面

复制代码
 1 #import <UIKit/UIKit.h>
 2 #import <AVFoundation/AVFoundation.h>
 3 @interface ScanQRcodeVC : UIViewController<AVCaptureMetadataOutputObjectsDelegate>{
 4 
 5     int  num;
 6     BOOL upOrdown;
 7     NSTimer *timer;
 8 }
 9 
10 @property (strong,nonatomic)AVCaptureDevice * device;
11 @property (strong,nonatomic)AVCaptureDeviceInput * input;
12 @property (strong,nonatomic)AVCaptureMetadataOutput * output;
13 @property (strong,nonatomic)AVCaptureSession * session;
14 @property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview;
15 @property (nonatomic, retain) UIImageView * line;
16 
17 @end
复制代码

// - ScanQRcodeVC.m

复制代码
  1 #define MainScreen_W [UIScreen mainScreen].bounds.size.width
  2 #define MainScreen_H [UIScreen mainScreen].bounds.size.height
  3 #define MiddleWidth 0.72*MainScreen_W  // 扫码框宽度
  4 #define Top_Height 0.2*MainScreen_H    // 扫码框距顶部距离
  5 #import "ScanQRcodeVC.h"
  6 #import "UIImage+mask.h"
  7 @interface ScanQRcodeVC (){
  8     bool _canOpen;
  9 }
 10 @end
 11 
 12 @implementation ScanQRcodeVC
 13 
 14 - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
 15     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 16     if (self) {
 17         _canOpen = NO;
 18     }
 19     return self;
 20 }
 21 
 22 
 23 - (void)viewDidLoad {
 24     [super viewDidLoad];
 25     [self creatUI];// 创建 UI
 26     [self setupCamera];
 27 
 28 }
 29 
 30 - (void)didReceiveMemoryWarning {
 31     [super didReceiveMemoryWarning];
 32     // Dispose of any resources that can be recreated.
 33 }
 34 
 35 - (void)setupCamera{
 36     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 37 
 38         if (!_device) {
 39             _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
 40             // Input
 41             _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
 42 
 43             // Output
 44             _output = [[AVCaptureMetadataOutput alloc]init];
 45             [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
 46 
 47             // Session
 48             _session = [[AVCaptureSession alloc]init];
 49             [_session setSessionPreset:AVCaptureSessionPresetHigh];
 50             if ([_session canAddInput:self.input]){
 51                 [_session addInput:self.input];
 52                 _canOpen = YES;
 53             }else{
 54                 dispatch_async(dispatch_get_main_queue(), ^{
 55                     // 回到主线程
 56                     UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"相机权限受限" message:@"请进入设置选项,点击此APP进行授权操作" preferredStyle:UIAlertControllerStyleAlert];
 57                     UIAlertAction *OKactuon = [UIAlertAction actionWithTitle:@"" style:UIAlertActionStyleDefault handler:nil];
 58                     [alertVC addAction:OKactuon];
 59                     [self presentViewController:alertVC animated:YES completion:nil];
 60                 });
 61             }
 62 
 63             if (_canOpen) {
 64                 if ([_session canAddOutput:self.output]){
 65                     [_session addOutput:self.output];
 66                 }
 67                 // 条形码/二维码
 68                 _output.metadataObjectTypes =[NSArray arrayWithObjects:AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeQRCode, nil];
 69 
 70                 // 只支持二维码
 71                 //_output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode];
 72 
 73                 _preview =[AVCaptureVideoPreviewLayer layerWithSession:self.session];
 74                 _preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
 75                 dispatch_async(dispatch_get_main_queue(), ^{
 76                     // 回到主线程
 77                     _preview.frame =CGRectMake(0,0,MainScreen_W,MainScreen_H);
 78                     [self.view.layer insertSublayer:self.preview atIndex:0];
 79                 });
 80             }
 81         }
 82 
 83         // Start
 84         if (_canOpen) {
 85             dispatch_async(dispatch_get_main_queue(), ^{
 86                 // 回到主线程
 87                 timer = [NSTimer scheduledTimerWithTimeInterval:.02 target:self selector:@selector(lineAnimation) userInfo:nil repeats:YES];
 88                 [_session startRunning];
 89             });
 90         }
 91     });
 92 }
 93 
 94 // 处理数据
 95 - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
 96 
 97     NSString *stringValue;// 扫码结果
 98     if ([metadataObjects count] >0){
 99 
100         // 播放扫描二维码的声音
101         SystemSoundID soundID;
102         NSString *strSoundFile = [[NSBundle mainBundle] pathForResource:@"noticeMusic" ofType:@"wav"];
103         AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:strSoundFile],&soundID);
104         AudioServicesPlaySystemSound(soundID);
105 
106         // 处理扫码结果
107         AVMetadataMachineReadableCodeObject * metadataObject = [metadataObjects objectAtIndex:0];
108         stringValue = metadataObject.stringValue;
109     }
110 
111     // 停止扫码
112     [timer invalidate];
113     timer = nil;
114     [_session stopRunning];
115 
116     UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"扫描结果" message:stringValue preferredStyle:UIAlertControllerStyleAlert];
117     UIAlertAction *OKaction = [UIAlertAction actionWithTitle:@"继续扫码" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
118         dispatch_async(dispatch_get_main_queue(), ^{
119             // 回到主线程
120             timer = [NSTimer scheduledTimerWithTimeInterval:.02 target:self selector:@selector(lineAnimation) userInfo:nil repeats:YES];
121             [_session startRunning];
122         });
123 
124     }];
125     [alertVC addAction:OKaction];
126     [self presentViewController:alertVC animated:YES completion:nil];
127 }
128 
129 // 停止扫码
130 - (void)viewWillDisappear:(BOOL)animated{
131 
132     [super viewWillDisappear:animated];
133     [timer invalidate];
134     timer = nil;
135     [_session stopRunning];
136 }
137 
138 
139 // 界面布局
140 - (void)creatUI{
141 
142     // 遮罩层
143     UIImageView *maskView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, MainScreen_W, MainScreen_H - 64)];
144     maskView.backgroundColor = [UIColor clearColor];
145 
146     // 扫描区View
147     maskView.image = [UIImage maskImageWithMaskRect:maskView.frame clearRect:CGRectMake((MainScreen_W-MiddleWidth)/2, Top_Height, MiddleWidth, MiddleWidth)];
148     [self.view addSubview:maskView];
149 
150     // 四角
151     CGFloat leadSpace = (MainScreen_W - MiddleWidth) / 2.0;
152     UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(leadSpace, Top_Height, MiddleWidth, MiddleWidth)];
153     imageView.image = [UIImage imageNamed:@"code_corner.png"];
154     [self.view addSubview:imageView];
155 
156     upOrdown = NO;
157     num = 0;
158     _line = [[UIImageView alloc] initWithFrame:CGRectMake(leadSpace, Top_Height, MiddleWidth, 12)];
159     _line.image = [UIImage imageNamed:@"scanLineOn.png"];
160     _line.contentMode = UIViewContentModeScaleToFill;
161     [self.view addSubview:_line];
162 
163     // 开关灯 button
164     UIButton * turnBtn = [UIButton buttonWithType:UIButtonTypeCustom];
165     [turnBtn setBackgroundImage:[UIImage imageNamed:@"lampDown.png"] forState:UIControlStateNormal];
166     [turnBtn setBackgroundImage:[UIImage imageNamed:@"lampOn.png"] forState:UIControlStateSelected];
167     turnBtn.frame = CGRectMake((MainScreen_W-60)/2.0,Top_Height + MiddleWidth + 95,60,60);
168     [turnBtn addTarget:self action:@selector(turnBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
169     [self.view addSubview:turnBtn];
170 }
171 
172 // line 动画
173 -(void)lineAnimation{
174 
175     CGFloat leadSpace = (MainScreen_W - MiddleWidth)/ 2;
176     if (upOrdown == NO) {
177         num ++;
178         _line.frame = CGRectMake(leadSpace, Top_Height+2*num, MiddleWidth, 12);
179         if (2*num >= MiddleWidth-12) {
180             upOrdown = YES;
181             _line.image = [UIImage imageNamed:@"scanLineDown.png"];
182         }
183     }else {
184         num --;
185         _line.frame = CGRectMake(leadSpace, Top_Height+2*num, MiddleWidth, 12);
186         if (num == 0) {
187             upOrdown = NO;
188             _line.image = [UIImage imageNamed:@"scanLineOn.png"];
189         }
190     }
191 }
192 
193 // 开/关判定状态
194 - (void)turnBtnEvent:(UIButton *)button_{
195 
196     button_.selected = !button_.selected;
197     if (button_.selected) {
198         [self turnTorchOn:YES];
199     }else{
200         [self turnTorchOn:NO];
201     }
202 }
203 
204 // 开/关灯
205 - (void)turnTorchOn:(bool)on{
206 
207     Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
208     if (captureDeviceClass != nil) {
209         AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
210 
211         if ([device hasTorch] && [device hasFlash]){
212 
213             [device lockForConfiguration:nil];
214             if (on) {
215                 [device setTorchMode:AVCaptureTorchModeOn];
216                 [device setFlashMode:AVCaptureFlashModeOn];
217             } else {
218                 [device setTorchMode:AVCaptureTorchModeOff];
219                 [device setFlashMode:AVCaptureFlashModeOff];
220             }
221             [device unlockForConfiguration];
222         }
223     }
224 }
225 
226 @end
复制代码

4 - 代码示例:如何使用

// - ViewController.m:点击屏幕进入扫码页面

复制代码
 1 #import "ViewController.h"
 2 #import "ScanQRcodeVC.h"
 3 @implementation ViewController
 4 
 5 - (void)viewDidLoad {
 6     [super viewDidLoad];
 7     self.view.backgroundColor = [UIColor whiteColor];
 8     self.navigationController.navigationBar.translucent = NO;// 禁止毛玻璃效果
 9 }
10 
11 // 修改标题
12 -(void)viewWillAppear:(BOOL)animated{
13     [super viewWillAppear:YES];
14     self.navigationItem.title = @"轻点屏幕,进入扫码页面";
15 
16 }
17 
18 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
19 
20     ScanQRcodeVC *scVC = [[ScanQRcodeVC alloc] init];
21     scVC.view.backgroundColor = [UIColor whiteColor];
22     self.navigationItem.title = @"返回";
23     [self.navigationController pushViewController:scVC animated:YES];
24 }
25 
26 
27 @end
复制代码

素材地址

https://pan.baidu.com/s/1fmB8bXRT6WaPjFh_PHlE_Q

1d7c

posted on   低头捡石頭  阅读(34)  评论(0编辑  收藏  举报

编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示