美文网首页
Swift 自定义扫码动画界面

Swift 自定义扫码动画界面

作者: 9岁就很6 | 来源:发表于2022-03-05 16:44 被阅读0次
    Untitled.gif

    效果图如上

    实现:
    1.创建一个控制器,设置控制器的view背景色为黑色,隐藏导航栏
    2.创建一个中心显示View,添加UI框框图,以及动画图,返回按钮,相册按钮布局。
    3.设置中心view的坐标、以及超出不显示。
    4.loadView添加一个蒙版View 设置背景色为黑色0.1透明,在 viewDidLayoutSubviews 在这个蒙版 绘制(裁剪)一个空白的view大小和中心显示vIew一样大。
    5.检查相机权限,初始化相机会话。
    6.开始铺捉相机,设置扫码回调代理,相机、相册自动识别。
    代码如下

    
    import UIKit
    import AVFoundation
    import PromiseKit
    
    class QRAnmitionVc: SBaseVc {
    
        @IBOutlet weak var centerView: UIView!
        @IBOutlet weak var anmitionImageTopCons: NSLayoutConstraint!
        @IBOutlet weak var tipsLable: UILabel!
        @IBOutlet weak var anmitionImage: UIImageView!
        @IBOutlet weak var backBtn: UIButton!
        
        //扫描成功的回调
        public var scanSuccessBlock: BlockWithParameters<String>?
        
        //摄像头会话
        private lazy var session : AVCaptureSession = {
            let session = AVCaptureSession()
             if session.canSetSessionPreset(.high){
                 session.sessionPreset = .high
            }
            return session
        }()
        
        //背景蒙版遮罩层
        private lazy var backgroundView : UIView = {
            let bgView = UIView(frame: self.view.bounds)
            bgView.backgroundColor = .black.withAlphaComponent(0.1)
            return bgView
        }()
        
        override func loadView() {
            super.loadView()
            view.addSubview(backgroundView)
            // 调整到父视图的最下面
            self.view.sendSubviewToBack(backgroundView)
        }
        
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            creatMaskLayer()
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            self.isHiddenNavBar = true
            view.backgroundColor = .black
            //超出部分不显示
            centerView.layer.masksToBounds = true
            beginAnmitionToView()
            checkCameraAuth()
            centerView.backgroundColor = .clear
        }
        
        
        //添加遮罩层 并且扣出一部分
        func creatMaskLayer(){
             
            let maskLayer = CAShapeLayer()
            maskLayer.fillRule = CAShapeLayerFillRule.evenOdd // 显示规则
    
            let basicPath = UIBezierPath(rect: view.frame) //底层
            let maskPath = UIBezierPath(roundedRect: centerView.frame, cornerRadius: 40) //自定义抠出来框框出来
            basicPath.append(maskPath)
    
            maskLayer.path = basicPath.cgPath
            backgroundView.layer.mask = maskLayer
            
            
        }
        //开始从下往下无限动画
        func beginAnmitionToView(){
            //无限循环的动画
            anmitionImage.transform = .identity
            
            UIView.animate(withDuration: 2) {
                self.anmitionImage.transform = CGAffineTransform(translationX: 0, y: self.centerView.view_height - self.anmitionImageTopCons.constant)
                 
            }completion: { [weak self] (falg)  in
                self?.beginAnmitionToView()
            }
             
            
        }
        //检查相机权限
       private func checkCameraAuth(){
           let status = AVCaptureDevice.authorizationStatus(for: .video)
           switch status {
           case .notDetermined:
               AVCaptureDevice.requestAccess(for: .video) { [weak self] (agree) in
                   agree ? self?.loadSession() : nil
               }
           case .restricted:
               print("无法访问摄像头")
           case .denied:
                print("请到手机系统的\n【设置】->【隐私】->【相册】\n开启相册的访问权限")
           case .authorized:
               self.loadSession()
           default:break
           }
             
        }
        
        //加载摄像头
        private func loadSession(){
            
            DispatchQueue.global().async {
                 
                // 捕捉设备
                guard let device = AVCaptureDevice.default(for: .video) else {
                    print("捕捉设备失败")
                    return
                }
                //输入
                guard let input = try? AVCaptureDeviceInput(device: device) else {
                    print("输入设备失败")
                    return
                }
                //输出
                let output:AVCaptureMetadataOutput = {
                   let output = AVCaptureMetadataOutput()
                    output.connection(with: .metadata)
                    return output
                }()
                
                //设置代理
                output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
                
                // 捕捉会话加入input和output
                if self.session.canAddInput(input) && self.session.canAddOutput(output) {
                    self.session.addInput(input)
                    self.session.addOutput(output)
                    // 设置元数据处理类型(注意, 一定要将设置元数据处理类型的代码添加到  会话添加输出之后)
                    output.metadataObjectTypes = [.ean13, .ean8, .upce, .code39, .code93, .code128, .code39Mod43, .qr]
                }
                DispatchQueue.main.async {
                    
                    // 指定预览层的捕捉会话
                    let preLayer = AVCaptureVideoPreviewLayer(session: self.session)
                    preLayer.videoGravity = .resizeAspectFill
                    preLayer.frame = self.view.bounds
                    
                    // 添加预览图层
                    self.view.layer.insertSublayer(preLayer, at: 0)
                    
                    // 启动会话
                    self.session.startRunning()
                    
                    // 3秒后更改提示
                    after(seconds: 3).done{ [weak self] in
                        self?.tipsLable.text = "请对准二维码,耐心等待"
                    }
                }
            }
        }
        
        @IBAction func backAction(_ sender: Any) {
            
            popAction()
        }
         
        @IBAction func openSystemPhotosAction(_ sender: Any) {
            
            guard UIImagePickerController.isSourceTypeAvailable(.photoLibrary) else {
                return
            }
            
            let imagePickerVC = UIImagePickerController()
            imagePickerVC.delegate = self
            present(imagePickerVC, animated: true, completion: nil)
        }
    }
    
    
    extension QRAnmitionVc : AVCaptureMetadataOutputObjectsDelegate{
        
        
        
        func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
             
            guard let codeObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject,
                  let resultStr = codeObject.stringValue else {
                return
            }
            
            //在这里做相对应的处理
            print("=======================识别出来的数据\(resultStr)============")
            
        }
        
        
    }
    // MARK: - UIImagePickerControllerDelegate
    
    extension QRAnmitionVc: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            
            guard let image = info[.originalImage] as? UIImage else {
                return
            }
            
            picker.dismiss(animated: true) { [weak self] in
                
                guard let resultStr = self?.detectorQrCode(image: image) else {
                    print("图片无效")
                    return
                }
                SLog(resultStr)
                self?.scanSuccessBlock?(resultStr)
            }
        }
        
        /// 识别图片二维码
         public func detectorQrCode(image: UIImage) -> String? {
            
            guard let ciImage = CIImage(image: image) else {
                return nil
            }
            
            guard let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyLow]) else {
                return nil
            }
            
            let results = detector.features(in: ciImage)
            
            guard let code = results.first as? CIQRCodeFeature else { return nil }
            
            return code.messageString
        }
    }
    
    
    
    

    相关文章

      网友评论

          本文标题:Swift 自定义扫码动画界面

          本文链接:https://www.haomeiwen.com/subject/jurmrrtx.html