草庐IT

Swift 版 二维码 扫码 iPad and iPhone

tito 2023-03-28 原文

importUIKit

importAVFoundation

private let scanAnimationDuration = 3.0//扫描时长

private let needSound = true //扫描结束是否需要播放声音

private let scanWidth : CGFloat = 300 //扫描框宽度

private let scanHeight : CGFloat = 300 //扫描框高度

private let isRecoScanSize = true //是否仅识别框内

private let scanBoxImagePath = "扫描框" //扫描框图片

private let scanLineImagePath = "扫描线" //扫描线图片

private let soundFilePath = "noticeMusic.caf" //声音文件

class ZWScanQRCodeVCJoe: UIViewController{


    letcancelBtn=UIButton()//取消返回按钮


    var scanPane: UIImageView!///扫描框

    var scanPreviewLayer : AVCaptureVideoPreviewLayer! //预览图层

    var output : AVCaptureMetadataOutput!

    var scanSession:  AVCaptureSession?


    lazyvarscanLine:UIImageView= {

        letscanLine =UIImageView()

        scanLine.frame=CGRect(x:0,y:0,width:scanWidth,height:3)

        scanLine.image=UIImage(named:scanLineImagePath)

        returnscanLine


    }()


    override func viewDidLoad(){

        super.viewDidLoad()


        //初始化界面

        self.initView()


        //初始化ScanSession

        setupScanSession()


        // 监听屏幕旋转

        //        NotificationCenter.default.addObserver(self, selector: #selector(receiverNotification), name: UIDevice.orientationDidChangeNotification, object: nil)

        self.receiverNotification()

    }


    @objc func receiverNotification() {

        setLayerOrientationByDeviceOritation()

    }


    overridefuncviewWillAppear(_animated:Bool){

        super.viewWillAppear(animated)

        startScan()

    }


    //初始化界面

    funcinitView()  {


        //取消按钮 返回按钮

        cancelBtn.frame = CGRect(x: 63*WidthW, y: 70*WidthW, width: 92*WidthW, height: 92*WidthW)

        //        cancelBtn.backgroundColor = UIColor.gray

        cancelBtn.setTitleColor(UIColor.white, for: .normal)

        cancelBtn.titleLabel?.font = UIFont.systemFont(ofSize: 18)

        cancelBtn.layer.cornerRadius = 3

        cancelBtn.clipsToBounds = true

        cancelBtn.tag=1

        cancelBtn.setImage(UIImage.init(named: "返回"), for: .normal)

        cancelBtn.addTarget(self, action: #selector(closeBtnClick), for: .touchUpInside)

        self.view.addSubview(cancelBtn)


        //


        scanPane=UIImageView()

        scanPane.frame=CGRect(x:300,y:100,width:400,height:400)

        scanPane.image = UIImage(named: scanBoxImagePath)

        self.view.addSubview(scanPane)


        //增加约束

        addConstraint()


        scanPane.addSubview(scanLine)

    }


    //返回页面

    @objc func closeBtnClick(){

        self.view.viewContainingController()?.navigationController?.popViewController(animated: false)

    }


    //扫描完成回调

    funcqrCodeCallBack(_codeString :String?) {

        self.confirm(title:"扫描结果",message: codeString,controller:self,handler: { (_)in

            //继续扫描

            self.startScan()

        })

    }


    func addConstraint() {

        scanPane.translatesAutoresizingMaskIntoConstraints = false

        //创建约束

        let widthConstraint = NSLayoutConstraint(item: scanPane as Any, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: scanWidth)

        let heightConstraint = NSLayoutConstraint(item: scanPane  as Any, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: scanHeight)

        let centerX = NSLayoutConstraint(item: scanPane as Any, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0)

        let centerY = NSLayoutConstraint(item: scanPane  as Any, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0)

        //添加多个约束

        view.addConstraints([widthConstraint,heightConstraint,centerX,centerY])

    }



    //初始化scanSession

    func setupScanSession(){


        do{

            //设置捕捉设备

            letdevice =AVCaptureDevice.default(for:AVMediaType.video)!

            //设置设备输入输出

            letinput =tryAVCaptureDeviceInput(device: device)


            letoutput =AVCaptureMetadataOutput()

            output.setMetadataObjectsDelegate(self,queue: DispatchQueue.main)

            self.output= output


            //设置会话

            let  scanSession =AVCaptureSession()

            scanSession.canSetSessionPreset(.high)


            ifscanSession.canAddInput(input){

                scanSession.addInput(input)

            }


            ifscanSession.canAddOutput(output){

                scanSession.addOutput(output)

            }


            //设置扫描类型(二维码和条形码)

            output.metadataObjectTypes= [

                .qr,

                .code39,

                .code128,

                .code39Mod43,

                .ean13,

                .ean8,

                .code93

            ]

            //预览图层

            letscanPreviewLayer =AVCaptureVideoPreviewLayer(session:scanSession)

            scanPreviewLayer.videoGravity=AVLayerVideoGravity.resizeAspectFill

            scanPreviewLayer.frame=view.layer.bounds

            self.scanPreviewLayer= scanPreviewLayer


            setLayerOrientationByDeviceOritation()


            //保存会话

            self.scanSession= scanSession


        }catch{

            //摄像头不可用

            self.confirm(title: "温馨提示", message: "摄像头不可用", controller: self)

            return

        }


    }


    func setLayerOrientationByDeviceOritation() {

        if(scanPreviewLayer == nil){

            return

        }

        scanPreviewLayer.frame = view.layer.bounds

        view.layer.insertSublayer(scanPreviewLayer, at: 0)

        letscreenOrientation =UIDevice.current.orientation

        if(screenOrientation == .portrait){

            scanPreviewLayer.connection?.videoOrientation = .portrait

        }elseif(screenOrientation == .landscapeLeft){

            scanPreviewLayer.connection?.videoOrientation = .landscapeRight

        }elseif(screenOrientation == .landscapeRight){

            scanPreviewLayer.connection?.videoOrientation = .landscapeLeft

        }elseif(screenOrientation == .portraitUpsideDown){

            scanPreviewLayer.connection?.videoOrientation = .portraitUpsideDown

        }else{

            scanPreviewLayer.connection?.videoOrientation = .landscapeRight

        }


        //设置扫描区域

        NotificationCenter.default.addObserver(forName:NSNotification.Name.AVCaptureInputPortFormatDescriptionDidChange,object:nil,queue:nil,using: { (noti)in

            if(isRecoScanSize){

                self.output.rectOfInterest = self.scanPreviewLayer.metadataOutputRectConverted(fromLayerRect: self.scanPane.frame)

            }else{

                self.output.rectOfInterest=CGRect(x:0,y:0,width:1,height:1)

            }

        })

    }


    //设备旋转后重新布局

    override func viewDidLayoutSubviews() {

        super.viewDidLayoutSubviews()

        setLayerOrientationByDeviceOritation()

    }


    //开始扫描

    fileprivate func startScan(){


        scanLine.layer.add(scanAnimation(), forKey: "scan")

        guardletscanSession =scanSessionelse{return}

        if!scanSession.isRunning

        {

            scanSession.startRunning()

        }

    }


    //扫描动画

    private func scanAnimation() -> CABasicAnimation{


        letstartPoint =CGPoint(x:scanLine.center.x  ,y:1)

        letendPoint =CGPoint(x:scanLine.center.x,y:scanHeight-2)


        lettranslation =CABasicAnimation(keyPath:"position")

        translation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)

        translation.fromValue=NSValue(cgPoint: startPoint)

        translation.toValue=NSValue(cgPoint: endPoint)

        translation.duration=scanAnimationDuration

        translation.repeatCount=MAXFLOAT

        translation.autoreverses=true


        returntranslation

    }


    //MARK: -

    //MARK: Dealloc

    deinit{

        ///移除通知

        NotificationCenter.default.removeObserver(self)

    }


}

//MARK: -

//MARK: AVCaptureMetadataOutputObjects Delegate

extension ZWScanQRCodeVCJoe : AVCaptureMetadataOutputObjectsDelegate

{



    //捕捉扫描结果

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {


        //停止扫描

        self.scanLine.layer.removeAllAnimations()

        self.scanSession!.stopRunning()


        //播放声音

        if(needSound){

            self.playAlertSound()

        }


        //扫描完成

        ifmetadataObjects.count>0{

            ifletresultObj = metadataObjects.firstas?AVMetadataMachineReadableCodeObject{

                self.qrCodeCallBack(resultObj.stringValue)

            }

        }

    }


    //弹出确认框

    func confirm(title:String?,message:String?,controller:UIViewController,handler: ( (UIAlertAction) -> Swift.Void)? = nil){


        letalertVC =UIAlertController(title: title,message: message,preferredStyle: .alert)


        letentureAction =UIAlertAction(title:"确定",style: .destructive,handler: handler)

        alertVC.addAction(entureAction)

        controller.present(alertVC,animated:true,completion:nil)


    }


    //播放声音

    func playAlertSound(){

        guardletsoundPath =Bundle.main.path(forResource:soundFilePath,ofType:nilelse{return}

        guardletsoundUrl =NSURL(string: soundPath)else{return}

        varsoundID:SystemSoundID=0

        AudioServicesCreateSystemSoundID(soundUrl, &soundID)

        AudioServicesPlaySystemSound(soundID)

    }

}

有关Swift 版 二维码 扫码 iPad and iPhone的更多相关文章

  1. Ruby -> 写入二维数组 - 2

    我正在处理http://prepwork.appacademy.io/mini-curriculum/array/中概述的数组问题我正在尝试创建函数my_transpose,它接受一个矩阵并返回其转置。我对写入二维数组感到很困惑!这是一个代码片段,突出了我的困惑。rows=[[0,1,2],[3,4,5],[6,7,8]]columns=Array.new(3,Array.new(3))putscolumns.to_s#Outputisa3x3arrayfilledwithnilcolumns[0][0]=0putscolumns.to_s#Outputis[[0,nil,nil],[

  2. 最新版人脸识别小程序 图片识别 生成二维码签到 地图上选点进行位置签到 计算签到距离 课程会议活动打卡日常考勤 上课签到打卡考勤口令签到 - 2

    技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下看,如果不符合你的需求,可以跳过。1-1,登录注册页可以看到登录页有注册入口,注册页如下我们的注册,需要管理员审核,审核通过后才可以正常登录使用小程序1-2,个人中心页登录成功以后,我们会进入个人中心页我们在个人中心页可以注册人脸,因为我们做人脸识别签到,需要先注册人脸才可以进行人脸比对,进

  3. ruby-on-rails - 在 rails 中生成二维码 - 2

    我想在ruby​​onrails中生成QR码,以便在我用rails编写的网站后台运行。看到这个http://code.google.com/p/qrcode-rails/但无法弄清楚如何让它为我工作。基本上在RoR中,我想:向生成器传递一个字符串、我的唯一代码、一个20个字符长度的数字(例如32032928889998887776)并生成一个名为“代码”_qr.jpg的图像并保存在资源文件夹中以附加到我的电子邮件中程序将发出。我该怎么做,有人知道吗?虽然我在问(不是很重要,我现在得到这个答案)但是我如何实现QR码读取,以从网络摄像头取回该代码?谢谢。 最佳答

  4. arrays - 在二维数组中搜索零并创建相应的行和列 0 - 2

    这是我的代码,可以运行,但它太大了。我想重构它。req_row=-1req_col=-1a.each_with_indexdo|row,index|row.each_with_indexdo|col,i|ifcol==0req_row=indexreq_col=ibreakendendendifreq_col>-1andreq_row>-1a.each_with_indexdo|row,index|row.each_with_indexdo|col,i|print(req_row==indexori==req_col)?0:colprint""endputs"\r"endend输入:二

  5. ruby - 如何在二维数组中查找 - 2

    我正在尝试学习如何在二维数组中进行搜索;例如:array=[[1,1],[1,2],[1,3],[2,1],[2,4],[2,5]]我想知道如何在数组中搜索格式为[1,y]的数组,然后显示其他y数字是什么:[1,2,3]。如果有人能帮助我了解如何仅使用数字进行搜索(因为我发现的很多示例都包含字符串或哈希),甚至可以帮助我了解在哪里寻找正确的资源,那将会很有帮助。 最佳答案 Ruby允许您通过在block参数中使用圆括号来查看元素。select和map只分配一个block参数,但您可以查看元素:array.select{|(x,y)|

  6. Ruby 获取二维数组中的对角线元素 - 2

    我正在尝试使用我的2Druby​​数组解决一些问题,当我进行数组切片时,我的LOC减少了很多。例如,require"test/unit"classLibraryTest我想知道是否有办法得到对角切片?假设我想从[0,0]开始并想要一个3的对角线切片。然后我会从[0,0]、[1,1]、[2,2]获取元素,我会得到一个数组[1,4,7]上面的例子。是否有任何神奇的单行ruby代码可以实现这一目标?3.次做{一些神奇的东西?} 最佳答案 puts(0..2).collect{|i|array[i][i]}

  7. ruby - 通过 ESC/POS 热敏打印机打印二维码? - 2

    我正在打印一些QR码(来自Ruby脚本),将ESC/POS命令写入EpsonTM-T20热敏打印机。顺便说一句,我正在编写一个简单的ESC/POS命令打印机“驱动程序”。我用的打印机是EpsonTM-T20(USB接口(interface))我正在使用serialportgem从Windows7主机进行一些测试。关于为打印格式化文本和线性条形码编写ESC/POS命令的一切都很好,但是我在理解打印QR代码的命令协议(protocol)时遇到问题,使用Epson提供的唯一可用文档(据我所知),请参阅:http://www.novopos.ch/client/EPSON/TM-T20/TM-

  8. arrays - 组合两个数组以在ruby中创建一个二维数组 - 2

    a=[1,2,3]b=[4,5,6]我如何将两个数组组合成一个二维数组?:[[1,4],[2,5],[3,6]] 最佳答案 尝试Array#zipa.zip(b)=>[[1,4],[2,5],[3,6]] 关于arrays-组合两个数组以在ruby中创建一个二维数组,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/12011294/

  9. ruby - 如何从 Rails 3 中的二维数组中查找记录? - 2

    我正在研究Rails3.0。我有一个二维数组。二维数组由用户数据和一个bool值组成。例如:[[user1,true],[user2,true],[user3,false]]看起来像这样:[[#,true],[#,true],[#,false],]我想有条件地查找/提取记录;说找到一整行Userid=2,它应该只返回第二行,即[#,true]有没有办法遍历这样的数组?如何实现? 最佳答案 my_array.select{|user,flag|user.id==2}所有拥有true标志的用户:my_array.select{|user

  10. ruby - 在 Ruby 中创建和迭代二维数组 - 2

    我对Ruby知之甚少,找不到创建二维数组的方法。任何人都可以提供一些片段或信息让我开始吗? 最佳答案 a=[[1,2],[3,4]]a.eachdo|sub|sub.eachdo|int|putsintendend#Output:#1#2#3#4或:a=[[1,2],[3,4]]a.eachdo|(x,y)|putsx+yend#Output:#3#7 关于ruby-在Ruby中创建和迭代二维数组,我们在StackOverflow上找到一个类似的问题: htt

随机推荐