参考: http://www.jianshu.com/p/203a48d64e71
代码: https://github.com/cirelir/2DBarcode
ViewController.swift
import UIKit
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
self.title = "首页"
let button = UIButton(frame: CGRect(x: (UIScreen.main.bounds.size.width-100) * 0.5, y: (UIScreen.main.bounds.size.height-30) * 0.5, width: 100, height: 30))
button.setTitle("扫一扫", for: UIControlState())
button.setTitleColor(UIColor.blue, for: UIControlState())
button.addTarget(self, action: #selector(ViewController.buttonAction(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(button)
}
func buttonAction(_ sender : AnyObject){
print("扫一扫")
let scanner = ScannerViewController()
self.present(scanner, animated: true, completion: nil);
//self.navigationController?.pushViewController(scanner, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
ScannerViewController.swift
import UIKit
import AVFoundation
class ScannerViewController: UIViewController,AVCaptureMetadataOutputObjectsDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate {
//相机显示视图
let cameraView = ScannerBackgroundView(frame: UIScreen.main.bounds)
let captureSession = AVCaptureSession()
override func viewDidLoad() {
super.viewDidLoad()
//self.title = "扫一扫"
self.view.backgroundColor = UIColor.black
//设置导航栏
/*let barButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.add, target: self, action: #selector(ScannerViewController.selectPhotoFormPhotoLibrary(_:)))
self.navigationItem.rightBarButtonItem = barButtonItem*/
let getFrmPhoto = UIButton(frame: CGRect(x: 10, y: 10, width: 200, height: 80));
getFrmPhoto.backgroundColor = UIColor.red
getFrmPhoto.setTitle("get From Photo", for: .normal)
getFrmPhoto.addTarget(self, action: #selector(selectPhotoFormPhotoLibrary(_:)), for: .touchUpInside)
self.view.addSubview(getFrmPhoto)
//
cameraView.frame.size.height -= 80;
cameraView.frame.origin.y += 80;
self.view.addSubview(cameraView)
//初始化捕捉设备(AVCaptureDevice),类型AVMdeiaTypeVideo
let captureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
let input :AVCaptureDeviceInput
//创建媒体数据输出流
let output = AVCaptureMetadataOutput()
//捕捉异常
do{
//创建输入流
input = try AVCaptureDeviceInput(device: captureDevice)
//把输入流添加到会话
captureSession.addInput(input)
//把输出流添加到会话
captureSession.addOutput(output)
}catch {
print("异常")
}
//创建串行队列
let dispatchQueue = DispatchQueue(label: "queue", attributes: [])
//设置输出流的代理
output.setMetadataObjectsDelegate(self, queue: dispatchQueue)
//设置输出媒体的数据类型
output.metadataObjectTypes = NSArray(array: [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]) as [AnyObject]
//创建预览图层
let videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
//设置预览图层的填充方式
videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
//设置预览图层的frame
videoPreviewLayer?.frame = cameraView.bounds
//将预览图层添加到预览视图上
cameraView.layer.insertSublayer(videoPreviewLayer!, at: 0)
//设置扫描范围
output.rectOfInterest = CGRect(x: 0.2, y: 0.2, width: 0.6, height: 0.6)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = true
self.scannerStart()
}
func scannerStart(){
captureSession.startRunning()
cameraView.scanning = "start"
}
func scannerStop() {
captureSession.stopRunning()
cameraView.scanning = "stop"
}
//扫描代理方法
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
print("_______")
if metadataObjects != nil && metadataObjects.count > 0 {
let metaData : AVMetadataMachineReadableCodeObject = metadataObjects.first as! AVMetadataMachineReadableCodeObject
print(metaData.stringValue)
DispatchQueue.main.async(execute: {
print("相机扫描结果:")
print(metaData.stringValue);
//let result = WebViewController()
//result.url = metaData.stringValue
//self.navigationController?.pushViewController(result, animated: true)
})
captureSession.stopRunning()
}
}
//从相册中选择图片
func selectPhotoFormPhotoLibrary(_ sender : AnyObject){
let picture = UIImagePickerController()
picture.sourceType = UIImagePickerControllerSourceType.photoLibrary
picture.delegate = self
self.present(picture, animated: true, completion: nil)
}
//选择相册中的图片完成,进行获取二维码信息
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage]
let imageData = UIImagePNGRepresentation(image as! UIImage)
let ciImage = CIImage(data: imageData!)
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyLow])
let array = detector?.features(in: ciImage!)
let result : CIQRCodeFeature = array!.first as! CIQRCodeFeature
print("从相册获取结果:");
print(result.messageString ?? String())
}
}
ScannerBackgroundView.swift
//
// ScannerBackgroundView.swift
// BDHome
//
// Created by Erwin on 16/6/17.
// Copyright © 2016年 BDHome. All rights reserved.
//
import UIKit
class ScannerBackgroundView: UIView {
//屏幕扫描区域视图
let barcodeView = UIView(frame: CGRect(x: UIScreen.main.bounds.size.width * 0.2, y: UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width * 0.6, height: UIScreen.main.bounds.size.width * 0.6))
//扫描线
let scanLine = UIImageView()
var scanning : String!
var timer = Timer()
override init(frame: CGRect) {
super.init(frame: frame)
barcodeView.layer.borderWidth = 1.0
barcodeView.layer.borderColor = UIColor.white.cgColor
self.addSubview(barcodeView)
//设置扫描线
scanLine.frame = CGRect(x: 0, y: 0, width: barcodeView.frame.size.width, height: 5)
scanLine.image = UIImage(named: "QRCodeScanLine")
//添加扫描线图层
barcodeView.addSubview(scanLine)
self.createBackGroundView()
self.addObserver(self, forKeyPath: "scanning", options: .new, context: nil)
timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(moveScannerLayer(_:)), userInfo: nil, repeats: true)
}
func createBackGroundView() {
let topView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height * 0.35))
let bottomView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.size.width * 0.6 + UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height * 0.65 - UIScreen.main.bounds.size.width * 0.6))
let leftView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width * 0.2, height: UIScreen.main.bounds.size.width * 0.6))
let rightView = UIView(frame: CGRect(x: UIScreen.main.bounds.size.width * 0.8, y: UIScreen.main.bounds.size.height * 0.35, width: UIScreen.main.bounds.size.width * 0.2, height: UIScreen.main.bounds.size.width * 0.6))
topView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
bottomView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
leftView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
rightView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
let label = UILabel(frame: CGRect(x: 0, y: 10, width: UIScreen.main.bounds.size.width, height: 21))
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 14)
label.textColor = UIColor.white
label.text = "将二维码/条形码放入扫描框内,即自动扫描"
bottomView.addSubview(label)
self.addSubview(topView)
self.addSubview(bottomView)
self.addSubview(leftView)
self.addSubview(rightView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if scanning == "start" {
timer.fire()
}else{
timer.invalidate()
}
}
//让扫描线滚动
func moveScannerLayer(_ timer : Timer) {
scanLine.frame = CGRect(x: 0, y: 0, width: self.barcodeView.frame.size.width, height: 12);
UIView.animate(withDuration: 2) {
self.scanLine.frame = CGRect(x: self.scanLine.frame.origin.x, y: self.scanLine.frame.origin.y + self.barcodeView.frame.size.height - 10, width: self.scanLine.frame.size.width, height: self.scanLine.frame.size.height);
}
}
}
其中要用的 扫描时上下移动的 横线 QRCodeScanLine@2x.png 看附件