可以参考,用swift实现的二维码扫描功能,包括扫码,闪光灯,颜色渐变等知识点
importAVFoundation
import UIKit
class YTScanVehicleViewController:UIViewController{
private letscanViewSize :CGFloat= 250
private letflashViewSize :CGFloat= 72
private letblueColor:UIColor=UIColor(red: 45/255.0, green: 100/255.0, blue: 245/255.0, alpha: 1)
private letgrayColor:UIColor=UIColor(red: 79/255.0, green: 85/255.0, blue: 108/255.0, alpha: 1)
private var scanView:YTScanQRCodeView?
private var flashView:UIView?
private var flashFlag :Bool=false
private let session:AVCaptureSession = AVCaptureSession()
private var layer:AVCaptureVideoPreviewLayer?
private lazy vargradientLayer:CAGradientLayer= {
letcolorArray:[CGColor] = [UIColor(red: 16/255.0, green: 69/255.0, blue: 150/255.0, alpha: 1).cgColor,UIColor(red: 0/255.0, green: 29/255.0, blue: 78/255.0, alpha: 1).cgColor]
letgradientLocations:[NSNumber] = [0.0, 1.0]
letgradientLayer =CAGradientLayer()
gradientLayer.colors= colorArray
gradientLayer.locations= gradientLocations
gradientLayer.frame=CGRect(x: 0, y: 0, width:flashViewSize, height:flashViewSize)
gradientLayer.masksToBounds=true;
gradientLayer.cornerRadius=flashViewSize/2
returngradientLayer
}()
public varscanResult: ((_code:Int,_result:String)->Void)?//声明扫描结果的闭包
overridefuncviewDidLoad() {
super.viewDidLoad()
initNavBar()
initView()
initScanView()
initCaptureSession()
}
//MARK: view 生命周期
override func viewWillAppear(_animated:Bool) {
super.viewWillAppear(animated);
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
}
override func viewDidDisappear(_animated:Bool) {
super.viewDidDisappear(animated)
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.shadowImage = nil
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK:初始化方法
private func initNavBar(){//导航栏
let leftItem :UIBarButtonItem=UIBarButtonItem(image:UIImage(named:"back"), style:UIBarButtonItemStyle.plain, target:self, action:#selector(navBack))
self.navigationItem.leftBarButtonItem = leftItem
self.navigationItem.title = "扫码"
}
private func initView(){//视图,权限
self.view.backgroundColor = UIColor.black;
if isCameraAviable() {
}else{
let alert:UIAlertController=UIAlertController(title:"提示", message:"没有相机权限", preferredStyle: .alert)
let cancelAction :UIAlertAction=UIAlertAction(title:"取消", style: .cancel,handler:nil)
let configAction :UIAlertAction=UIAlertAction(title:"去配置", style: .default, handler: {
action in
let urlObj = URL(string:UIApplicationOpenSettingsURLString)
if#available(iOS10.0, *){
UIApplication.shared.open(urlObj!, options: [:], completionHandler:nil)
}else{
UIApplication.shared.openURL(urlObj!)
}
})
alert.addAction(cancelAction)
alert.addAction(configAction)
self.present(alert, animated:true, completion:nil)
return
}
}
private funcinitScanView(){//扫描视图
scanView = YTScanQRCodeView(frame: CGRect(x:0, y: 0, width: scanViewSize, height: scanViewSize));
scanView!.center = CGPoint(x: self.view.center.x, y: self.view.center.y-40)
scanView!.bgColor = blueColor.cgColor
scanView!.layer.cornerRadius = 4
scanView!.layer.masksToBounds = true
self.view.addSubview(scanView!)
let scanLine:UILabel=UILabel(frame:CGRect(x: 10, y: 0, width:scanViewSize-20, height: 1))
scanLine.backgroundColor = blueColor
scanLine.tag= 99
scanView?.addSubview(scanLine)
let tipLabel:UILabel=UILabel(frame:CGRect(x: 0, y:self.view.center.y+100, width:self.view.frame.size.width, height: 20))
tipLabel.font=UIFont.systemFont(ofSize: 14)
tipLabel.textColor=UIColor.white
tipLabel.textAlignment = NSTextAlignment.center
tipLabel.text="请将二维码对准扫描框"
self.view.addSubview(tipLabel);
flashView = UIView(frame: CGRect(x:self.view.center.x-flashViewSize/2,y:self.view.frame.height-30-flashViewSize, width: flashViewSize, height: flashViewSize))
flashView?.backgroundColor = grayColor
flashView?.layer.cornerRadius = flashViewSize/2
flashView?.layer.masksToBounds = true
self.view.addSubview(flashView!)
let tap : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(flashSwitch))
flashView?.addGestureRecognizer(tap)
let flashImg:UIImageView = UIImageView(frame: CGRect(x:flashViewSize/2-flashViewSize/6, y: flashViewSize/2-flashViewSize/6, width: flashViewSize/3, height: flashViewSize/3))
flashImg.image=UIImage(named:"flashlight")
flashView?.addSubview(flashImg)
}
privatefuncinitCaptureSession(){//多媒体,摄像头初始化
session.sessionPreset = .high
do{
if let device : AVCaptureDevice = AVCaptureDevice.default(for: .video){
letput =tryAVCaptureDeviceInput(device: device)
ifsession.canAddInput(put) {
session.addInput(put)
}
}
}catch {
print("初始化失败")
}
if session.inputs.count == 0 {
letalert:UIAlertController=UIAlertController(title:"提示", message:"没有找到摄像头设备", preferredStyle: .alert)
letcancelAction :UIAlertAction=UIAlertAction(title:"确定", style: .cancel,handler:nil)
alert.addAction(cancelAction)
self.present(alert, animated:true, completion:nil)
}else{
let out = AVCaptureMetadataOutput()
out.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
out.rectOfInterest = self.scanView!.bounds
ifsession.canAddOutput(out) {
self.session.addOutput(out)
let metaDataTypeList = [AVMetadataObject.ObjectType.qr,AVMetadataObject.ObjectType.code39,AVMetadataObject.ObjectType.ean13,AVMetadataObject.ObjectType.ean8,AVMetadataObject.ObjectType.code128,AVMetadataObject.ObjectType.code93,AVMetadataObject.ObjectType.pdf417,AVMetadataObject.ObjectType.interleaved2of5]
out.metadataObjectTypes= metaDataTypeList
}
let previewLayer:AVCaptureVideoPreviewLayer= AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
previewLayer.frame=CGRect(x: 5, y: 5, width:scanViewSize-10, height:scanViewSize-10)
scanView!.layer.insertSublayer(previewLayer, at: 0)
session.startRunning()//开始扫描
addScanAnimation()//开始动画
}
}
//MARK :其他方法
privatefuncisCameraAviable() ->Bool{
let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
returnauthStatus != .restricted&& authStatus != .denied
}
privatefuncopenOrCloseTorch(){
guard let device = AVCaptureDevice.default(for: AVMediaType.video) else {
print("无法获取到您的设备")
return
}
if device.hasTorch&& device.isTorchAvailable{
try? device.lockForConfiguration()
ifflashFlag{
device.torchMode= .on
}else{
device.torchMode= .off
}
}
}
privatefuncaddScanAnimation(){
letanimation :CABasicAnimation=CABasicAnimation(keyPath:"position.y")
animation.fromValue=NSNumber(value: 10)
animation.toValue=NSNumber(value:Float(scanViewSize)-10)
animation.autoreverses=true
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
animation.repeatCount=MAXFLOAT
animation.duration= 2
let label : UILabel = scanView?.viewWithTag(99) as! UILabel
label.layer.add(animation, forKey:"scanAnimation")
}
private func removsScanAnimation(){
let label : UILabel = scanView?.viewWithTag(99) as! UILabel
label.layer.removeAnimation(forKey:"scanAnimation")
label.isHidden=true
}
private func endScan(){
if session.isRunning {
session.stopRunning()
}
flashFlag=false
openOrCloseTorch()
removsScanAnimation()
}
//MARK:OC方法
@objc func navBack(){
self.navigationController?.popViewController(animated: true)
endScan()//退出页面时,停止扫描,关闭闪光灯,关闭动画
}
@objc func flashSwitch(_tap:UIGestureRecognizer){
ifflashFlag{
flashView?.backgroundColor = grayColor
if (flashView?.layer.sublayers?.count)! > 0 {
letlayer :CALayer= (flashView?.layer.sublayers?.first)!
layer.removeFromSuperlayer()
}
flashFlag=false
}else{
flashView?.layer.insertSublayer(self.gradientLayer, at: 0)
flashFlag=true
}
//开启或关闭闪光灯
openOrCloseTorch()
}
}
extension YTScanVehicleViewController:AVCaptureMetadataOutputObjectsDelegate{
func metadataOutput(_output:AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection:AVCaptureConnection) {
ifmetadataObjects.count> 0 {
endScan()//停止扫描
let result : AVMetadataMachineReadableCodeObject = metadataObjects.first as! AVMetadataMachineReadableCodeObject
ifletresultStr = result.stringValue{
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
ifletresultClourse =self.scanResult{
resultClourse(0,resultStr)
}
}else{
ifletresultClourse =self.scanResult{
resultClourse(1,"")
}
}
}
}
}
二维码扫描视图类
import UIKit
class YTScanQRCodeView:UIView{
var bgColor:CGColor?
override init(frame:CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_rect:CGRect) {
let cxt :CGContext = UIGraphicsGetCurrentContext()!
letborderLineWidth :CGFloat = 1
letcornorLineWidth :CGFloat = 12
letcornorLength :CGFloat= 25
cxt.setLineWidth(borderLineWidth)
ifletbColor =bgColor{
cxt.setStrokeColor(bColor)
}
cxt.addRect(self.bounds)
cxt.strokePath()
cxt.setLineWidth(cornorLineWidth)
//左上角
cxt.move(to:CGPoint(x: 0, y: 0))
cxt.addLine(to:CGPoint(x: cornorLength, y: 0))
cxt.strokePath()
cxt.move(to:CGPoint(x: 0, y: 0))
cxt.addLine(to:CGPoint(x: 0, y: cornorLength))
cxt.strokePath()
//右上角
cxt.move(to:CGPoint(x:self.frame.size.width, y: 0))
cxt.addLine(to:CGPoint(x:self.frame.size.width-cornorLength, y: 0))
cxt.strokePath()
cxt.move(to:CGPoint(x:self.frame.size.width, y: 0))
cxt.addLine(to:CGPoint(x:self.frame.size.width, y:cornorLength ))
cxt.strokePath()
//右下角
cxt.move(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))
cxt.addLine(to:CGPoint(x:self.frame.size.width, y:self.frame.size.height-cornorLength))
cxt.strokePath()
cxt.move(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))
cxt.addLine(to:CGPoint(x:self.frame.size.width-cornorLength, y:self.frame.size.height))
cxt.strokePath()
//左下角
cxt.move(to:CGPoint(x:0, y:self.frame.size.height))
cxt.addLine(to:CGPoint(x: 0, y:self.frame.size.height-cornorLength))
cxt.strokePath()
cxt.move(to:CGPoint(x: 0, y:self.frame.size.height))
cxt.addLine(to:CGPoint(x:cornorLength, y:self.frame.size.height))
cxt.strokePath()
}
}
网友评论