iOS-仿微信掃一掃秋麸、長按識別二維碼,以及一句話生成二維碼
1驯耻、二維碼簡介
在iOS中二維碼的實質是一個字符串,一般用于制作名片孽水,手機電商購物鏈家城看、微信掃一掃测柠,微信支付缘滥,QQ加好友,以及移動支付等赃阀。其中用的最廣的當然是大家熟知的支付寶擎颖,微信和QQ了搂捧。既然二維碼用途這么廣,很多APP里面都或多或少有二維碼的存在王凑,那么下面就掃一掃二維碼聋丝,長按識別二維碼,以及生成二維碼從無到有的過程百姓,和遇到的坑分享給大家每篷。
2焦读、進入主題
在一定的程度之后,相信大家都有封裝的思想仑嗅,那么本文有幾個分裝介紹給大家:
JWDQRCodeViewController.h 掃一掃控制器分裝
JWDPreView.h 掃一掃動畫界面封裝
JWDCreatQRCodeView.h 生成二維碼封裝
下面就這三個類進行介紹
3仓技、JWDQRCodeViewController 掃一掃控制器分裝
JWDQRCodeViewController.h
.h 沒什么可說的,給外界的接口
#import <UIKit/UIKit.h>
@interface JWDQRCodeViewController : UIViewController
- (instancetype)initWithFrame:(CGRect)frame;
@end
JWDQRCodeViewController.m
導入相應的頭文件阔逼,必須的變量
其中SafariServices/SafariServices.h框架用于url跳轉控制器地沮,是iOS9之后的新特性,可以方便打開相應的網(wǎng)頁界面危融。
#import "JWDQRCodeViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "JWDPreView.h"
#import <SafariServices/SafariServices.h>
@interface JWDQRCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property(nonatomic, strong)AVCaptureDeviceInput *deviceInput;//!< 攝像頭輸入
@property(nonatomic, strong)AVCaptureMetadataOutput *metadataOutput;//!< 輸出
@property(nonatomic, strong)AVCaptureSession *session;//!< 會話
@property(nonatomic, strong)AVCaptureVideoPreviewLayer *previewLayer;//!< 預覽
@property(nonatomic, strong)JWDPreView *preView;//!< <#value#>
@end
@implementation JWDQRCodeViewController
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super init];
if (self) {
self.view.frame = frame;
[self initUiConfig];
}
return self;
}
-(void)initUiConfig {
// 默認為后置攝像頭
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
self.deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:NULL];
// 解析輸入的數(shù)據(jù)
self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];
[self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 會話
self.session = [[AVCaptureSession alloc] init];
if ([self.session canAddInput:self.deviceInput]){
[self.session addInput:self.deviceInput];
}
if([self.session canAddOutput:self.metadataOutput]){
[self.session addOutput:self.metadataOutput];
}
// 設置數(shù)據(jù)采集質量
self.session.sessionPreset = AVCaptureSessionPresetHigh;
// 設置需要解析的數(shù)據(jù)類型,二維碼
self.metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
JWDPreView *preView = [[JWDPreView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
self.preView = preView;
[self.view addSubview:preView];
preView.session = self.session;
preView.backPreView = ^(JWDPreView *backPreView){
[self.session stopRunning];
[self dismissViewControllerAnimated:YES completion:nil];
// 銷毀定時器
if (backPreView.timer){
[backPreView.timer invalidate];
backPreView.timer = nil;
}
};
[self.session startRunning];
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
for (AVMetadataMachineReadableCodeObject *obj in metadataObjects) {
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
[self presentViewController:safariVC animated:YES completion:nil];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
上面建立采集二維碼的過濾器蛋勺,和基本的輸入和輸出的建立率寡,鏈接輸入和輸出的會話建立冶共,以及開啟和適當?shù)臅r候關閉會話的處理。
切記這里要使用攝像頭家卖,所以要者info.plist 里面設置訪問權限
在解析獲取捕捉到的信息后會在代理 AVCaptureMetadataOutputObjectsDelegate的下面方法里面獲取信息
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
for (AVMetadataMachineReadableCodeObject *obj in metadataObjects) {
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
[self presentViewController:safariVC animated:YES completion:nil];
}
}
獲取到相應的數(shù)據(jù)后可以在這里面做一些業(yè)務邏輯上荡,本人在這里就用到SFSafariViewController控制器來代開網(wǎng)頁
好了下面介紹掃描界面
4.JWDPreView 掃一掃動畫界面封裝
JWDPreView.h
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@class JWDPreView;
typedef void(^backPreView) (JWDPreView *preView);
@interface JWDPreView : UIView
- (instancetype)initWithFrame:(CGRect)frame;
@property(nonatomic, strong)AVCaptureSession *session;//!< 渲染會話層
@property (nonatomic, copy) backPreView backPreView;//!< 返回按鈕回調
@property(nonatomic, strong)NSTimer *timer;//!< <#value#>
@end
JWDPreView.m
#import "JWDPreView.h"
@interface JWDPreView ()
{
UIImageView *_imageView;
UIImageView *_lineImageView;
UIButton *_backBtn;
}
@end
@implementation JWDPreView
// 修改當前View 的圖層類別
+(Class)layerClass {
return [AVCaptureVideoPreviewLayer class];
}
-(void)setSession:(AVCaptureSession *)session {
_session = session;
AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)self.layer;
layer.session = session;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initUiConfig];
}
return self;
}
- (void)initUiConfig {
_backBtn = [[UIButton alloc] initWithFrame:CGRectMake(30, 50, 40, 20)];
[_backBtn setTitle:@"返回" forState:UIControlStateNormal];
[_backBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_backBtn addTarget:self action:@selector(backButtonDid) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_backBtn];
_imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pick_bg.png"]];
_imageView.frame = CGRectMake(self.bounds.size.width * 0.5 - 140, self.bounds.size.height * 0.5 - 140, 280, 280);
[self addSubview:_imageView];
_lineImageView = [[UIImageView alloc] initWithFrame:CGRectMake(30, 10, 220, 2)];
_lineImageView.image = [UIImage imageNamed:@"line.png"];
[_imageView addSubview:_lineImageView];
_timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(animation) userInfo:nil repeats:YES];
}
- (void)animation
{
[UIView animateWithDuration:2.8 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
_lineImageView.frame = CGRectMake(30, 260, 220, 2);
} completion:^(BOOL finished) {
_lineImageView.frame = CGRectMake(30, 10, 220, 2);
}];
}
- (void)backButtonDid {
if (self.backPreView){
self.backPreView(self);
}
}
@end
在.m中一個重點就是 掃一掃界面瀏覽layer的修改
在UIView中默認的 為 [CALayer class]而這不是二維碼掃描所需的layer,所以修改逛薇。這樣強轉后的layer才有session的會話設置
// 修改當前View 的圖層類別
+(Class)layerClass {
return [AVCaptureVideoPreviewLayer class];
}
-(void)setSession:(AVCaptureSession *)session {
_session = session;
AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)self.layer;
layer.session = session;
}
5.JWDCreatQRCodeView 生成二維碼封裝
JWDCreatQRCodeView.h
一句話生成二維碼的接口
#import <UIKit/UIKit.h>
@interface JWDQRCodeViewController : UIViewController
- (instancetype)initWithFrame:(CGRect)frame;
@end
JWDCreatQRCodeView.m
#import "JWDQRCodeViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "JWDPreView.h"
#import <SafariServices/SafariServices.h>
@interface JWDQRCodeViewController ()<AVCaptureMetadataOutputObjectsDelegate>
@property(nonatomic, strong)AVCaptureDeviceInput *deviceInput;//!< 攝像頭輸入
@property(nonatomic, strong)AVCaptureMetadataOutput *metadataOutput;//!< 輸出
@property(nonatomic, strong)AVCaptureSession *session;//!< 會話
@property(nonatomic, strong)AVCaptureVideoPreviewLayer *previewLayer;//!< 預覽
@property(nonatomic, strong)JWDPreView *preView;//!< <#value#>
@end
@implementation JWDQRCodeViewController
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super init];
if (self) {
self.view.frame = frame;
[self initUiConfig];
}
return self;
}
-(void)initUiConfig {
// 默認為后置攝像頭
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
self.deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:NULL];
// 解析輸入的數(shù)據(jù)
self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];
[self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
// 會話
self.session = [[AVCaptureSession alloc] init];
if ([self.session canAddInput:self.deviceInput]){
[self.session addInput:self.deviceInput];
}
if([self.session canAddOutput:self.metadataOutput]){
[self.session addOutput:self.metadataOutput];
}
// 設置數(shù)據(jù)采集質量
self.session.sessionPreset = AVCaptureSessionPresetHigh;
// 設置需要解析的數(shù)據(jù)類型啤呼,二維碼
self.metadataOutput.metadataObjectTypes = @[AVMetadataObjectTypeQRCode];
JWDPreView *preView = [[JWDPreView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
self.preView = preView;
[self.view addSubview:preView];
preView.session = self.session;
preView.backPreView = ^(JWDPreView *backPreView){
[self.session stopRunning];
[self dismissViewControllerAnimated:YES completion:nil];
// 銷毀定時器
if (backPreView.timer){
[backPreView.timer invalidate];
backPreView.timer = nil;
}
};
[self.session startRunning];
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
for (AVMetadataMachineReadableCodeObject *obj in metadataObjects) {
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:obj.stringValue]];
[self presentViewController:safariVC animated:YES completion:nil];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
好了官扣,這樣介紹完了惕蹄,上面的幾個類就可以實現(xiàn)功能治专。
6.下面介紹
ViewController繼承基本的全部功能
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "JWDPreView.h"
#import <SafariServices/SafariServices.h>
#import "JWDQRCodeViewController.h"
#import "JWDCreatQRCodeView.h"
@interface ViewController ()
@property(nonatomic, strong)UIButton *code;//!< <#value#>
@property(nonatomic, strong)UIButton *code1;//!< <#value#>
@property(nonatomic, strong)JWDCreatQRCodeView *creatQRCodeView;//!< <#value#>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat X = (self.view.frame.size.width - 2*100)/3.0;
_code = [[UIButton alloc] initWithFrame:CGRectMake(X, 100, 100, 60)];
_code.backgroundColor = [UIColor yellowColor];
[_code setTitle:@"掃一掃" forState:UIControlStateNormal];
[_code setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_code addTarget:self action:@selector(codeDidClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_code];
_code1 = [[UIButton alloc] initWithFrame:CGRectMake(2*X + 100, 100, 100, 60)];
_code1.backgroundColor = [UIColor yellowColor];
[_code1 setTitle:@"生成二維碼" forState:UIControlStateNormal];
[_code1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
[_code1 addTarget:self action:@selector(code1DidClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_code1];
}
- (void)codeDidClick {
JWDQRCodeViewController *QRCodeVC = [[JWDQRCodeViewController alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self presentViewController:QRCodeVC animated:YES completion:nil];
}
- (void)code1DidClick {
UIView *qrCodeView = [[UIView alloc] initWithFrame:CGRectMake((self.view.frame.size.width-200)*0.5, 250, 200, 220)];
[self.view addSubview:qrCodeView];
JWDCreatQRCodeView *creatQRCodeView = [[JWDCreatQRCodeView alloc] initWithFrame:CGRectMake(0, 0, 200, 200) withQRCodeString:@"http://www.reibang.com/users/5b9953c3d3ad/latest_articles" withQRCodeCenterImage:@"me"];
self.creatQRCodeView = creatQRCodeView;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, 200, 20)];
label.text = @"長按識別二維碼看靠,跳轉網(wǎng)頁";
label.font = [UIFont systemFontOfSize:12];
label.textAlignment = NSTextAlignmentCenter;
[qrCodeView addSubview:label];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressDid)];
creatQRCodeView.userInteractionEnabled = YES;
[creatQRCodeView addGestureRecognizer:longPress];
[qrCodeView addSubview:creatQRCodeView];
}
- (void)longPressDid{
// 0.創(chuàng)建上下文
CIContext *context = [[CIContext alloc] init];
// 1.創(chuàng)建一個探測器
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:@{CIDetectorAccuracy: CIDetectorAccuracyLow}];
// 2.直接開始識別圖片,獲取圖片特征
CIImage *imageCI = [[CIImage alloc] initWithImage:self.creatQRCodeView.image];
NSArray<CIFeature *> *features = [detector featuresInImage:imageCI];
CIQRCodeFeature *codef = (CIQRCodeFeature *)features.firstObject;
// 彈框
UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"識別圖中二維碼" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alertC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"取消");
}]];
__weak ViewController *weakSelf = self;
[alertC addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:codef.messageString]];
[weakSelf presentViewController:safariVC animated:YES completion:nil];
}]];
[self presentViewController:alertC animated:YES completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
完結,小小的一個demo嗦哆,可能還有不完善的地方老速,當你發(fā)現(xiàn)了還請不吝賜教,謝謝橘券。
最后奉上demo 地址 https://github.com/weidongjiang/JWD-QRCode
如果對你有用旁舰,解決了你的問題,得到了幫助箭窜,還請star磺樱。相互學習。