基于swift3.0
1.创建设备
//MARK: 绘画
lazy var session: AVCaptureSession = {
let ss = AVCaptureSession()
return ss
}()
//MARK: 设备
lazy var device: AVCaptureDevice = {
let dev = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
return dev!
}()
//MARK: 输入设备
lazy var deviceInput: AVCaptureDeviceInput? = {
do {
let input = try AVCaptureDeviceInput(device: self.device)
return input
}catch {
print(error)
return nil
}
}()
//MARK: 输出设备
lazy var deviceOutput: AVCaptureMetadataOutput = {
let metaOut = AVCaptureMetadataOutput()
/* metaOut.metadataObjectTypes = metaOut.availableMetadataObjectTypes
metaOut.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
这两句不能写在
session.addInput(deviceInput)
session.addOutput(deviceOutput)
之前
*/
return metaOut
}()
2.创建扫描边框
//MARK: 边框
lazy var imageView: UIImageView = {
let imgView = UIImageView(image: UIImage(named: "qrcode_border"))
imgView.frame.origin.x = (self.view.frame.width - 200) * 0.5
imgView.frame.origin.y = 200
imgView.frame.size = CGSize(width: 200, height: 200)
return imgView
}()
3.添加扫描线和扫描线的动画
lazy var scanLine: UIImageView = {
let lineImageView = UIImageView(image: UIImage(named: "QRCode_ScanLine"))
lineImageView.frame = CGRect(x: self.imageView.frame.origin.x, y: self.imageView.frame.origin.y, width: self.imageView.frame.size.width, height: 2)
return lineImageView
}()
func scanAnimation() -> CABasicAnimation {
let startPoint = CGPoint(x: self.scanLine.center.x, y: self.imageView.frame.origin.y)
let endPoint = CGPoint(x: self.imageView.center.x, y: self.imageView.frame.maxY - 2)
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(cgPoint: startPoint)
animation.toValue = NSValue(cgPoint: endPoint)
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
animation.duration = 1
animation.autoreverses = true
animation.repeatCount = 10000
return animation
}
4.添加预览图层
//MARK: 预览图层
lazy var previewLayer: AVCaptureVideoPreviewLayer = {
let layer = AVCaptureVideoPreviewLayer(session: self.session)
layer?.frame = UIScreen.main.bounds
return layer!
}()
5.开始扫描
func startScan() -> Void {
if !session.canAddInput(deviceInput) {
return
}
if !session.canAddOutput(deviceOutput) {
return
}
scanLine.layer.add(scanAnimation(), forKey: "haha")
session.addInput(deviceInput)
session.addOutput(deviceOutput)
deviceOutput.metadataObjectTypes = deviceOutput.availableMetadataObjectTypes
deviceOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
//设置扫面区域
deviceOutput.rectOfInterest = (previewLayer.metadataOutputRectOfInterest(for: self.imageView.frame))
session.startRunning()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
title = "扫描二维码"
view.addSubview(imageView)
view.addSubview(scanLine)
view.layer.insertSublayer(previewLayer, at: 0)
startScan()
}
6.扫面完成后的代理(没仔细处理)
extension QRCodeViewController : AVCaptureMetadataOutputObjectsDelegate {
public func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
// [corners { 0.6,0.8 0.9,0.8 0.9,0.2 0.6,0.2 }, time 149347505505458, stringValue "http://weixin.qq.com/r/ydlCWn3EqSDWrTk594zb"]
if metadataObjects == nil || metadataObjects.count == 0 {
return
}
for object in metadataObjects {
if object is AVMetadataMachineReadableCodeObject {
let metadataObj = metadataObjects.last as! AVMetadataMachineReadableCodeObject
// print(metadataObj.corners)
let pointS : AVMetadataMachineReadableCodeObject = previewLayer.transformedMetadataObject(for: metadataObj) as! AVMetadataMachineReadableCodeObject
drawCorners(codeObject: pointS)
}
}
}
private func drawCorners(codeObject: AVMetadataMachineReadableCodeObject) {
clearSubView()
let layer = CAShapeLayer()
layer.fillColor = UIColor.clear.cgColor
layer.strokeColor = UIColor.red.cgColor
let pointDic = codeObject.corners
// let poindArr = CGPoint.init(dictionaryRepresentation: pointDic)
let aa = pointDic![0] as! NSDictionary
let point0 = CGPoint.init(dictionaryRepresentation: aa)
let bb = pointDic![1] as! NSDictionary
let point1 = CGPoint.init(dictionaryRepresentation: bb)
let cc = pointDic![2] as! NSDictionary
let point2 = CGPoint.init(dictionaryRepresentation: cc)
let dd = pointDic![3] as! NSDictionary
let point3 = CGPoint.init(dictionaryRepresentation: dd)
let path = UIBezierPath()
path.move(to: point0!)
path.addLine(to: point1!)
path.addLine(to: point2!)
path.addLine(to: point3!)
path.close()
layer.path = path.cgPath
drawLayer.addSublayer(layer)
}
func clearSubView() -> Void {
if drawLayer.sublayers == nil || drawLayer.sublayers?.count == 0{
return
}
for subLayer in drawLayer.sublayers! {
subLayer.removeFromSuperlayer()
}
}
}