在项目中经常用到二维码的扫描,这里测试了下swift下二维码的实现
- 首先在界面中定义一个扫描的区域的View,一般这个区域放到界面的正中间
class ScanView: UIView
/// 扫描的区域的宽度
var scanWidth:CGFloat = 300
/// 扫描区域
var scanCenterView:UIView?
/// 扫描背景边框
var scanBoard:UIImageView?
/// 扫描的动态图片
var scanImageView:UIImageView?
override init(frame: CGRect) {
super.init(frame: frame)
//-------------------------- 扫描区域的视图---------------------
//添加扫描区域
scanCenterView = UIView(frame: CGRect(x: 0, y: 0, width: scanWidth, height: scanWidth))
scanCenterView?.center=center
//超出部分剪去
scanCenterView?.clipsToBounds=true
addSubview(scanCenterView!)
//扫描边框
scanBoard=UIImageView(frame: CGRectMake(scanCenterView!.frame.origin.x-2, scanCenterView!.frame.origin.y-2, scanCenterView!.frame.size.width+3, scanCenterView!.frame.size.height+3))
// scanBoard?.backgroundColor=UIColor.redColor()
scanBoard?.image=UIImage(named: "qrcode_border")
//超出部分剪去
scanBoard?.clipsToBounds=true
addSubview(scanBoard!)
}
2.为了使得扫描的界面更好看,使得扫描框周边的界面半透明化
override func drawRect(rect: CGRect) {
super.drawRect(rect)
//得到图形上下文
let context=UIGraphicsGetCurrentContext()
///非扫码区域半透明
CGContextSetRGBFillColor(context, 0, 0, 0, 0.5)
let leftMargin = (frame.size.width-scanWidth)/2
let topMargin = (frame.size.height-scanWidth)/2
//填充矩形
//扫码区域上面填充
var rect = CGRectMake(0, 0, frame.size.width, topMargin)
CGContextFillRect(context, rect)
//扫码区域左边填充
rect=CGRectMake(0, topMargin, leftMargin, frame.size.height- topMargin*2)
CGContextFillRect(context, rect)
//扫码区域右边填充
rect=CGRectMake(leftMargin+scanWidth, topMargin, leftMargin, frame.size.height-topMargin*2)
CGContextFillRect(context, rect)
//扫码区域下面填充
rect = CGRectMake(0, topMargin+scanWidth, frame.size.width,topMargin)
CGContextFillRect(context, rect)
//执行绘画
CGContextStrokePath(context)
}
3.同时定义一个扫描的动画,看上去更生动,类似正在扫描一样
/**
开始动画
*/
private func startAnimation(){
UIView.animateWithDuration(1.3) { () -> Void in
UIView.setAnimationRepeatCount(MAXFLOAT)
self.scanImageView?.frame=CGRectMake(self.scanImageView!.frame.origin.x, self.scanImageView!.frame.origin.y+self.scanCenterView!.frame.size.height+100, (self.scanImageView?.frame.size.width)!, (self.scanImageView?.frame.size.height)!)
}
}
/**
停止动画
*/
func stopAnimation()
{
scanImageView?.removeFromSuperview()
}
- 在自定义的扫描区域View构建完成后,现在开始调用这个界面进行扫描,在调用之前要调用系统的相机AVCaptureDevice,初始化一些参数
class ViewController: UIViewController{
/// 扫描视图
var scanView:ScanView!
/// 扫描设备
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
// MARK: - 懒加载
private lazy var input: AVCaptureDeviceInput? = {
return try? AVCaptureDeviceInput(device: self.device)
}()
// 会话
private lazy var session : AVCaptureSession = AVCaptureSession()
// 创建预览图层
private lazy var previewLayer: AVCaptureVideoPreviewLayer = {
let layer = AVCaptureVideoPreviewLayer(session: self.session)
layer.frame = UIScreen.mainScreen().bounds
return layer
}()
private lazy var output:AVCaptureMetadataOutput = {
let out = AVCaptureMetadataOutput()
let viewRect = self.view.frame
// 扫描区域 (也是扫描框的frame)
let scanRect = self.scanView.scanCenterView?.frame
let x = scanRect!.origin.y / viewRect.height;
let y = scanRect!.origin.x / viewRect.width;
let width = scanRect!.height / viewRect.height;
let height = scanRect!.width / viewRect.width;
// 设置可探测区域
// rectOfInterset设置: CGRectMake(扫描区域y的起点/屏幕的高度, 扫描区域的x/屏幕的宽度, 扫描区域的高/屏幕的高, 扫描区域的宽度/屏幕的宽度)
out.rectOfInterest = CGRect(x: x, y: y, width: width, height: height)
return out
}()
}
- 开始调用扫描二维码
/**
初始化二维码
*/
private func scanQRCode(){
// 1.判断输入能否添加到会话中
if !session.canAddInput(input){
return
}
// 2.判断输出能够添加到会话中
if !session.canAddOutput(output)
{
return
}
// 3.添加输入和输出到会话中
session.addInput(input)
session.addOutput(output)
// 4.设置输出能够解析的数据类型
// 注意点: 设置数据类型一定要在输出对象添加到会话之后才能设置
// output.metadataObjectTypes =
// [AVMetadataObjectTypeQRCode,
// AVMetadataObjectTypeCode39Code,
// AVMetadataObjectTypeCode128Code,
// AVMetadataObjectTypeCode93Code,
// AVMetadataObjectTypeCode39Mod43Code,
// AVMetadataObjectTypeEAN8Code,
// AVMetadataObjectTypeEAN13Code]
output.metadataObjectTypes = output.availableMetadataObjectTypes
// 5.设置监听监听输出解析到的数据
output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
// 6.添加预览图层
view.layer.insertSublayer(previewLayer, atIndex: 0)
previewLayer.frame = view.bounds
// 7.添加容器图层
view.layer.addSublayer(containerLayer)
containerLayer.frame = view.bounds
// 8.开始扫描
session.startRunning()
}
6.对于扫描的结果在其代理方法中实现
//MARK: - AVCaptureMetadataOutputObjectsDelegate
extension ViewController : AVCaptureMetadataOutputObjectsDelegate{
/// 只要扫描到结果就会调用
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!)
{
// 1.显示结果
print("-----扫描到的------");
let alertView = UIAlertView(title:"", message: "", delegate: self, cancelButtonTitle: "确定")
if metadataObjects.count>0 {
let metadataObject = metadataObjects.last
if metadataObject!.isKindOfClass(AVMetadataMachineReadableCodeObject) {
let code = metadataObject as! AVMetadataMachineReadableCodeObject
print(code)
//码类型 Code128 QRCode
print("码类型\(code.type)")
//码内容
print("码内容\(code.stringValue)")
alertView.message=code.stringValue
alertView.show()
//4个字典,分别 左上角-右上角-右下角-左下角的 坐标百分百,可以使用这个比例抠出码的图像 code.corners
//如果是个网址的话 打开这个网址
// UIApplication.sharedApplication().openURL(NSURL(string: code.stringValue)!)
scanView.stopAnimation()
session.stopRunning()
}
}
}
}
通过代理方法可以用来处理扫描到的结果在进行相关的处理
源码可以去这查看https://github.com/Cutehf/QRCode-Swift