wordpress 站内搜索代码,网络网站制作过程,一个网站上线需要什么,汕头网站建设seo外包引言
随着iOS 7引入AV Foundation框架#xff0c;二维码扫描功能已经成为iOS应用程序中不可或缺的一部分。现今#xff0c;几乎每个应用都充分利用这一功能#xff0c;为用户提供了诸如扫码登录、扫码填充等丰富多彩的便捷体验。这项技术不仅丰富了应用功能#xff0c;也为…引言
随着iOS 7引入AV Foundation框架二维码扫描功能已经成为iOS应用程序中不可或缺的一部分。现今几乎每个应用都充分利用这一功能为用户提供了诸如扫码登录、扫码填充等丰富多彩的便捷体验。这项技术不仅丰富了应用功能也为开发人员的调试工作带来了极大便利。在本博客中我们将深入探讨如何实现自定义二维码扫描为您打开更广阔的应用开发可能性。
主要类-AVCaptureMetadataOutput 在二维码扫描中我们仍然以AVCaptureSession为核心配置输入(AVCaptureDeviceInput)和输出(AVCaptureOutput)。特别是在输出方面我们使用AVCaptureMetadataOutput来专门处理摄像头捕获到的二维码、条形码等元数据。
通过设置metadataObjectTypes属性我们可以灵活地指定要捕获的元数据类型如二维码、QR码、条形码等。这样的设置允许我们精确控制扫描的类型提高识别效率。
通过实现AVCaptureMetadataOutputObjectsDelegate代理我们能够在识别到指定类型的元数据时触发相应的代理方法从而处理这些元数据。这为开发者提供了处理扫描结果的机会使得在应用中集成二维码扫描功能变得更为灵活和可定制。 //MARK:检测到指定类型元数据
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray__kindof AVMetadataObject * *)metadataObjects fromConnection:(AVCaptureConnection *)connection{} 功能实现 为了使描述更清晰我们将二维码识别和元数据处理分别放置到两个不同的类里面来处理。 PHCameraController主要负责启动会话开启进行二维码识别。 PHPreviewView我们在这个view里面来处理和呈现元数据。 PHCameraController 和其它媒体捕捉的功能几乎一样配置会话启动会话。不同的是会话的输出实现另外我们还在里面定义了一个协议当有二维码被识别到时会调用这个协议中的方法将元数据传递给PHPreviewView。 接口 下面看一下PHCameraController中接口的定义。 #import AVFoundation/AVFoundation.h
NS_ASSUME_NONNULL_BEGIN
protocol PHCodeDetectionDelegate NSObject
- (void)didDetectCodes:(NSArray *)codes;
end
interface PHCameraController : NSObject
property(nonatomic,weak)id PHCodeDetectionDelegate codeDetectionDelegate;
property(nonatomic,strong,readonly)AVCaptureSession * captureSession;///设置会话
- (BOOL)setupSession:(NSError **)error;
///开始会话
- (void)startSession;
///停止会话
- (void)stopSession;end
NS_ASSUME_NONNULL_END 外漏了一个只读的AVCaptureSession和三个核心的方法。以及一个codeDetectionDelegate。 实现 接下来看一下PHCameraController的实现会相对复杂一点但我们只需要将关注点放到配置会话输出以及AVCaptureMetadataOutputObjectsDelegate的代理方法上面。 设置会话 #import PHCameraController.h
#import UIKit/UIKit.h
interface PHCameraController ()AVCaptureMetadataOutputObjectsDelegate
property(nonatomic,strong)AVCaptureMetadataOutput * metadataOutput;
end
implementation PHCameraController- (NSString *)sessionPreset{return AVCaptureSessionPreset640x480;
}//MARK:设置会话
- (BOOL)setupSession:(NSError *__autoreleasing _Nullable *)error{self.captureSession [[AVCaptureSession alloc] init];self.captureSession.sessionPreset self.sessionPreset;if (![self setupSessionInputs:error]) {return NO;}if (![self setupSessionOutputs:error]) {return NO;}return YES;
}配置会话输入
//MARK:配置会话输入
- (BOOL)setupSessionInputs:(NSError *__autoreleasing _Nullable *)error{BOOL success [super setupSessionInputs:error];if (success) {if (self.activeCamera.autoFocusRangeRestrictionSupported) {if ([self.activeCamera lockForConfiguration:error]) {self.activeCamera.autoFocusRangeRestriction AVCaptureAutoFocusRangeRestrictionNear;[self.activeCamera unlockForConfiguration];}}}return success;
} 配置会话输出 //MARK:配置会话输出
- (BOOL)setupSessionOutputs:(NSError *__autoreleasing _Nullable *)error{self.metadataOutput [[AVCaptureMetadataOutput alloc] init];if ([self.captureSession canAddOutput:self.metadataOutput]) {[self.captureSession addOutput:self.metadataOutput];NSArray * metadataObjectTypes [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeAztecCode,AVMetadataObjectTypeUPCECode];self.metadataOutput.metadataObjectTypes metadataObjectTypes;dispatch_queue_t mainQueue dispatch_get_main_queue();[self.metadataOutput setMetadataObjectsDelegate:self queue:mainQueue];return YES;}else{return NO;}
}识别到指定类型元数据的回调 //MARK:检测到指定兴趣点的代理
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray__kindof AVMetadataObject * *)metadataObjects fromConnection:(AVCaptureConnection *)connection{[self.codeDetectionDelegate didDetectCodes:metadataObjects];
} PHPreviewView 主要负责显示预览画面及显示元数据内容。 接口 #import UIKit/UIKit.h
#import AVFoundation/AVFoundation.hNS_ASSUME_NONNULL_BEGINinterface PHPreviewView : UIViewproperty(nonatomic,strong)AVCaptureSession * session;endNS_ASSUME_NONNULL_END 实现 initWithFrame:方法 interface PHPreviewView ()PHCodeDetectionDelegateendimplementation PHPreviewView- (id)initWithFrame:(CGRect)frame{if ([super initWithFrame:frame]) {[self setupView];}return self;
}- (void)setupView{self.codeLayers {}.mutableCopy;self.previewLayer.videoGravity AVLayerVideoGravityResizeAspect;
}遵守了一个PHCodeDetectionDelegate协议。 设置预览layer的画面填充方式。 重写方法 同样我们通过重写layerClass类方法来返回一个AVCaptureVideoPreviewLayer类。 通过重写session的setter来为AVCaptureVideoPreviewLayer设置session。 通过重写session的getter来返回当前session。 (Class)layerClass{return [AVCaptureVideoPreviewLayer class];
}- (void)setSession:(AVCaptureSession *)session{[(AVCaptureVideoPreviewLayer*)self.layer setSession:session];
}- (AVCaptureSession *)session{return [(AVCaptureVideoPreviewLayer*)self.layer session];
} 定义previewLayer的getter //MARK:当前显示画面layer
- (AVCaptureVideoPreviewLayer *)previewLayer{return (AVCaptureVideoPreviewLayer *)self.layer;
} 实现PHCodeDetectionDelegate代理
//MARK:代理 检测到条码
- (void)didDetectCodes:(NSArray *)codes{if (codes.count 0) {return;}NSArray * transformedCodes [self transformedCodesFromCodes:codes];for (AVMetadataMachineReadableCodeObject * code in transformedCodes) {NSString * stringValue code.stringValue;if (self.codeArrowLayers.count 0) {self.codeArrowLayers [self makeCornersLayers];}for (int i 0; i self.codeArrowLayers.count; i ) {if (i code.corners.count) {break;}CAShapeLayer * layer self.codeArrowLayers[i];[self.previewLayer addSublayer:layer];layer.path [self bezierPathWithCodes:code.corners index:i].CGPath;}NSLog(String :%,stringValue);}[self.delegate didDetectCodes:codes];
} 关于这个方法我们需要分成几部分来理解。 首先调用了一个transformedCodesFromCodes:方法只是我们自己定义的方法在里面我们只是调用了AVCaptureVideoPreviewLayer提供的坐标转发方法将设备坐标空间元数据对象转换为视图坐标空间对象实现如下 //MARK:坐标转换
- (NSArray *)transformedCodesFromCodes:(NSArray *)codes{NSMutableArray * transformedCodes [NSMutableArray array];for (AVMetadataObject * code in codes) {AVMetadataObject * transformedCode [self.previewLayer transformedMetadataObjectForMetadataObject:code];[transformedCodes addObject:transformedCode];}return transformedCodes;
} 读取到的AVMetadataMachineReadableCodeObject对象里面会有一个bounds和corners两个数组bounds属性提供了识别码的按坐标轴对其的矩形边界corners属性提供角点字典表示的NSArray。后一个属性更实用因为使用它可以让我们构建一个与条码的角点坐标紧密对其的Bezier路径。当然还有一个更重要的属性是stringValue也就是我们从二维码中读取到的内容。 示例中我们使用它的corners属性绘制出了二维码的顶点轮廓实现如下 创建轮廓layer //MARK: makeCornersLayers
- (NSArray *)makeCornersLayers{CAShapeLayer * leftTop [[CAShapeLayer alloc] init];CAShapeLayer * leftBottom [[CAShapeLayer alloc] init];CAShapeLayer * rightBottom [[CAShapeLayer alloc] init];CAShapeLayer * rightTop [[CAShapeLayer alloc] init];NSArray * array [leftTop,leftBottom,rightBottom,rightTop];for (CAShapeLayer * layer in array) {layer.strokeColor [UIColor redColor].CGColor;layer.fillColor [UIColor clearColor].CGColor;layer.lineWidth 2.0;}return array;
} 绘制轮廓path - (UIBezierPath *)bezierPathWithCodes:(NSArray *)codes index:(NSInteger)index{CGPoint point;CGPointMakeWithDictionaryRepresentation((CFDictionaryRef)codes[index], point);CGPoint prePoint CGPointZero;CGPoint postPoint CGPointZero;switch (index) {case 0:{prePoint CGPointMake(point.x, point.y 10);postPoint CGPointMake(point.x 10, point.y);}break;case 1:{prePoint CGPointMake(point.x, point.y - 10);postPoint CGPointMake(point.x 10, point.y);}break;case 2:{prePoint CGPointMake(point.x - 10, point.y);postPoint CGPointMake(point.x, point.y - 10);}break;case 3:{prePoint CGPointMake(point.x, point.y 10);postPoint CGPointMake(point.x - 10, point.y);}break;}UIBezierPath * path [UIBezierPath bezierPath];[path moveToPoint:prePoint];[path addLineToPoint:point];[path addLineToPoint:postPoint];return path;
} 最后代理调用didDetectCodes:方法将结果传递到视图控制器并停止会话。 视图控制器实现 import ViewController.h
#import PHPreviewView
#import PHCameraController.hinterface ViewController ()PHPreviewViewDelegate///相机控制
property(nonatomic,strong)PHCameraController * controller;
///预览view
property(nonatomic,strong)PHPreviewView * previewView;endimplementation ViewController- (void)viewDidLoad {[super viewDidLoad];[self setupView];
}- (void)setupView{[self addPreviewView];[self configController];
}//MARK: 添加预览视图
- (void)addPreviewView{self.previewView [[PHPreviewView alloc] initWithFrame:self.view.bounds];[self.view addSubview:self.previewView];self.previewView.delegate self;
}- (void)didDetectCodes:(NSArray *)codes{[self.controller stopSession];
}- (BOOL)prefersStatusBarHidden{return YES;
}end结语 当我们深入研究了上述简单的二维码扫描示例后我们不禁会发现这只是冰山一角。iOS提供了丰富的功能和灵活的接口让我们能够进一步深挖二维码扫描的世界。举例来说我们可以定义扫描范围通过调整参数来适应各种应用场景从而提高扫描的精准度和效率。 此外iOS还支持各种花哨的识别效果可以为用户提供更为生动和愉悦的扫描体验。通过巧妙运用动画、声音等元素我们能够使二维码扫描不仅仅是一项实用的功能更是一种与用户互动的方式。 在这个不断创新和演变的移动应用时代探索二维码扫描功能的可能性就像打开了一扇通往无限可能性的大门。无论是为了提升用户体验还是为了创造独特的应用功能二维码扫描都为开发者提供了丰富的创作空间。让我们在不断探索的道路上发现更多精彩的可能性吧。