iOS-swfit-原生二维码扫描
2018-08-16 本文已影响0人
Cary9396
前段时间项目有个二维码扫描的需求,于是就研究了一下。发现了挺多第三方,例如ZBar,ZXing。第三方的确功能强大,但并不一定是最好选择。 如果你的项目只是需要简单的扫描功能。并不需要它特别强大的话,完全可以抛弃第三方,自己写原生代码。实现起来非常简单。今天我们来说一个swfit版本的原生二维码。
废话不多说,上代码:
override func viewDidLoad() {
super.viewDidLoad()
judgeCameraPermission()
setupView()
}
首先我们需要判读一下相机设备是否可用,记得在plist文件添加相机权限,这个不多说了。
func judgeCameraPermission() {
//拒绝,受限制
let status = AVCaptureDevice.authorizationStatus(for: .video)
if status == .restricted || status == .denied {
print("没有权限使用!")
}
else if status == .notDetermined {
AVCaptureDevice.requestAccess(for: .video) { (allow) in
if allow {
print("同意了")
self.initSession()
self.initScanView()
self.session?.startRunning()
}
else {
print("拒绝了")
}
}
}
else {
initSession()
}
}
用session生成一个AVCaptureVideoPreviewLayer添加到view的layer上,实时显示摄像头捕捉的内容:
func initScanView() {
let layer = AVCaptureVideoPreviewLayer(session: session!)
layer.videoGravity = .resizeAspectFill
layer.frame = UIScreen.main.bounds
view.layer.insertSublayer(layer, at: 0)
}
创建session 设置采集时的参数:
func initSession() {
let device = AVCaptureDevice.default(for: .video)
do {
let input = try AVCaptureDeviceInput(device: device!) //创建摄像头输入流
let output = AVCaptureMetadataOutput() //创建输出流
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
//设置扫描区域
let widthS = 300 / xScreenHeight
let heightS = 300 / xScreenWidth
output.rectOfInterest = CGRect(x: (1-widthS)/2, y: (1-heightS)/2, width: widthS, height: heightS)
session = AVCaptureSession()
//采集率质量
session?.sessionPreset = .high
session?.addInput(input)
session?.addOutput(output)
output.metadataObjectTypes = [.qr,.ean13,.ean8,.code128]
} catch let err as NSError {
print("发生错误:\(String(describing: err.localizedFailureReason))")
}
}
设置扫描时候的UI界面:
func setupView() {
title = "扫描二维码"
view.backgroundColor = UIColor.white
view.addSubview(MaskView(frame: UIScreen.main.bounds))
if session != nil {
initScanView()
}
}
class MaskView: UIView {
var lineLayer:CALayer!
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.black.withAlphaComponent(0.1)
lineLayer = CALayer()
lineLayer.frame = CGRect(x: (frame.width-300)/2, y: (frame.height-300)/2, width: 300, height: 2)
lineLayer.contents = UIImage(named: "line")?.cgImage
layer.addSublayer(lineLayer)
resumeAnimation()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect:CGRect){
let width:CGFloat = rect.size.width
let height:CGFloat = rect.size.height
let pickingWidth:CGFloat = 300
let pickingHeight:CGFloat = 300
let context = UIGraphicsGetCurrentContext()
context?.saveGState()
context?.setFillColor(red:0.1,green:0.1,blue:0.1,alpha:0.35)
let pickingRect = CGRect(x: (width-pickingWidth)/2, y: (height-pickingHeight)/2, width: pickingWidth, height: pickingHeight)
let pickingPath = UIBezierPath(rect: pickingRect)
let bezierRect = UIBezierPath(rect: rect)
bezierRect.append(pickingPath)
bezierRect.usesEvenOddFillRule = true
bezierRect.fill()
context?.setLineWidth(2)
context?.setStrokeColor(UIColor.orange.cgColor)
pickingPath.stroke()
layer.contentsGravity = kCAGravityCenter
}
func stopAnimation() {
lineLayer.removeAnimation(forKey: "translationY")
}
func resumeAnimation() {
let basic = CABasicAnimation(keyPath: "transform.translation.y")
basic.fromValue = 0
basic.toValue = 300
basic.duration = 2
basic.repeatCount = Float(NSIntegerMax)
lineLayer.add(basic, forKey: "translationY")
}
}
扫描后执行的delegate方法:
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
if metadataObjects.count > 0 {
let metadata = metadataObjects.first as! AVMetadataMachineReadableCodeObject
let alert = UIAlertController(title: "扫描结果", message:metadata.stringValue, preferredStyle:.alert)
let action = UIAlertAction(title: "确定", style: .default, handler: nil)
alert.addAction(action)
present(alert, animated: true, completion: nil)
}
}
页面进来的时候记得开启session,离开时记得关闭session:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
session?.startRunning()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
session?.stopRunning()
}
此时便已大功告成,已经实现了一个简单的二维码识别的功能。识别相册图片二维码的功能后期再加上。
具体可查看Demo:
https://github.com/WisdomWang/CAQRCode
如果你需要oc版本的 给你推荐一个 这个作者写的功能也很全面。你可以参考写自己想要的二维码功能。链接:
https://github.com/kingsic/SGQRCode
识别相册二维码图片功能已加,请查看上方Demo。