如何在条形码扫描仪上绘制的矩形动画?

发布于 2025-01-25 06:57:34 字数 3651 浏览 3 评论 0原文

我在Swift中创建了一个条形码扫描仪控件。扫描仪工作正常,我可以绘制一个扫描区域盒覆盖。我试图根据扫描的成功使盒子闪光绿色或红色。我添加了一个延迟的动画,但是它无法正常工作。盒子的颜色确实发生了变化,但在持续时间内没有缓慢的动画。它只是立即改变。 I.希望盒子闪烁绿色,然后恢复为原始颜色。

我想知道我一开始如何绘制盒子是否有什么应有的作用。也许我正在修改的cashapelayer与动画不兼容?

class BarcodeScanner: UIView, AVCaptureMetadataOutputObjectsDelegate {
       
    var scanBoxLayer: CAShapeLayer!
    
    func preparePreviewLayer() {
        self.layer.sublayers?.removeAll()
        
        captureSession = AVCaptureSession()
        
        guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else {
            return
        }
        
        let videoInput: AVCaptureDeviceInput

        do {
            videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
        } catch {
            return
        }

        if (captureSession.canAddInput(videoInput)) {
            captureSession.addInput(videoInput)
        } else {
            return
        }

        let metadataOutput = AVCaptureMetadataOutput()
        
        if (captureSession.canAddOutput(metadataOutput)) {
            captureSession.addOutput(metadataOutput)

            metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            metadataOutput.metadataObjectTypes = [.ean8, .ean13, .pdf417, .qr, .code39, .code128]
        } else {
            return
        }

        scanPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        scanPreviewLayer.frame = self.layer.bounds
        scanPreviewLayer.videoGravity = .resizeAspectFill
                    
        self.layer.addSublayer(scanPreviewLayer)

        // Here is where I draw the scan box
        drawScanBox()
    }

    func drawScanBox() {
        let path = UIBezierPath(rect: scanBox())
        
        scanBoxLayer = CAShapeLayer()
                    
        scanBoxLayer.path = path.cgPath
        scanBoxLayer.strokeColor = UIColor.systemYellow.cgColor
        scanBoxLayer.lineWidth = 2
        scanBoxLayer.fillColor = UIColor.clear.cgColor
        scanBoxLayer.shadowColor = UIColor.systemYellow.cgColor
        scanBoxLayer.shadowOpacity = 1.0
        scanBoxLayer.shadowRadius = 5.0
        
        self.layer.addSublayer(scanBoxLayer)
    }
    
    func scanBox() -> CGRect {
        let height: CGFloat = self.scanPreviewLayer.frame.size.height
        let width: CGFloat = self.scanPreviewLayer.frame.size.width
        
        return self.bounds.insetBy(dx: width / 5, dy: height / 3)
    }

    func flash() {        
        UIView.animate(
            withDuration: 3.0,
            delay: 0.0,
            options: [.repeat, .autoreverse],
            animations: {
                self.scanBoxLayer.strokeColor = UIColor.systemGreen.cgColor
                self.scanBoxLayer.shadowColor = UIColor.systemGreen.cgColor
            },
            completion: nil
        )
    }
    
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
         if let metadataObject = metadataObjects.first {
            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
            
            if let barcode = readableObject.stringValue {
                // Here is where I want to make the scan box flash
                flash()
                
                self.delegate?.scanComplete(code: barcode)
            }
        }
    }
    
}

“

有人可以告诉我我是否缺少某些东西?

谢谢!

I created a barcode scanner control in Swift. The scanner works fine and I am able to draw a scan area box overlay. I am trying to make the box flash green or red depending on the success of the scan. I've added an animation with a delay but it does not work properly. The color of the box does change but there isn't a slow animation for the duration period. it just changes immediately. I. would like the box to flash green and then revert back to the original color.

I am wondering if it has something to due with how I am drawing the box in the first place. Perhaps the CAShapeLayer that I am modifying isn't compatible with animations?

class BarcodeScanner: UIView, AVCaptureMetadataOutputObjectsDelegate {
       
    var scanBoxLayer: CAShapeLayer!
    
    func preparePreviewLayer() {
        self.layer.sublayers?.removeAll()
        
        captureSession = AVCaptureSession()
        
        guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else {
            return
        }
        
        let videoInput: AVCaptureDeviceInput

        do {
            videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
        } catch {
            return
        }

        if (captureSession.canAddInput(videoInput)) {
            captureSession.addInput(videoInput)
        } else {
            return
        }

        let metadataOutput = AVCaptureMetadataOutput()
        
        if (captureSession.canAddOutput(metadataOutput)) {
            captureSession.addOutput(metadataOutput)

            metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            metadataOutput.metadataObjectTypes = [.ean8, .ean13, .pdf417, .qr, .code39, .code128]
        } else {
            return
        }

        scanPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        scanPreviewLayer.frame = self.layer.bounds
        scanPreviewLayer.videoGravity = .resizeAspectFill
                    
        self.layer.addSublayer(scanPreviewLayer)

        // Here is where I draw the scan box
        drawScanBox()
    }

    func drawScanBox() {
        let path = UIBezierPath(rect: scanBox())
        
        scanBoxLayer = CAShapeLayer()
                    
        scanBoxLayer.path = path.cgPath
        scanBoxLayer.strokeColor = UIColor.systemYellow.cgColor
        scanBoxLayer.lineWidth = 2
        scanBoxLayer.fillColor = UIColor.clear.cgColor
        scanBoxLayer.shadowColor = UIColor.systemYellow.cgColor
        scanBoxLayer.shadowOpacity = 1.0
        scanBoxLayer.shadowRadius = 5.0
        
        self.layer.addSublayer(scanBoxLayer)
    }
    
    func scanBox() -> CGRect {
        let height: CGFloat = self.scanPreviewLayer.frame.size.height
        let width: CGFloat = self.scanPreviewLayer.frame.size.width
        
        return self.bounds.insetBy(dx: width / 5, dy: height / 3)
    }

    func flash() {        
        UIView.animate(
            withDuration: 3.0,
            delay: 0.0,
            options: [.repeat, .autoreverse],
            animations: {
                self.scanBoxLayer.strokeColor = UIColor.systemGreen.cgColor
                self.scanBoxLayer.shadowColor = UIColor.systemGreen.cgColor
            },
            completion: nil
        )
    }
    
    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
         if let metadataObject = metadataObjects.first {
            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
            
            if let barcode = readableObject.stringValue {
                // Here is where I want to make the scan box flash
                flash()
                
                self.delegate?.scanComplete(code: barcode)
            }
        }
    }
    
}

Screenshot

Can anyone please tell me if I am missing something?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文