iOS:相机在第一次加载视图控制器时无法识别二维码

Posted

技术标签:

【中文标题】iOS:相机在第一次加载视图控制器时无法识别二维码【英文标题】:iOS: Camera does not recognize QR Code on first load of view controller 【发布时间】:2016-10-21 08:25:49 【问题描述】:

我有一个小应用程序,它可以读取二维码进行登录,或者提供手动输入代码和登录的可能性。 该应用程序启动并直接进入登录(查看)。当我尝试扫描不起作用的二维码时 - 从未调用委托/从未引发事件。

我采用了 Larry OBrien http://www.knowing.net/index.php/2013/10/09/natively-recognize-barcodesqr-codes-in-ios-7-with-xamarin-ios/ 的方法

并为此创建了我自己的 ScannerView 类:

public sealed partial class ScannerView : UIView

    private readonly AVCaptureVideoPreviewLayer _layer;
    public AVCaptureSession Session  get; 
    private readonly AVCaptureMetadataOutput _metadataOutput;

    public event EventHandler<AVMetadataMachineReadableCodeObject> MetadataFound = delegate  ;
    public ScannerView (IntPtr handle) : base (handle)
    
        Session = new AVCaptureSession();
        var camera = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video);
        var input = AVCaptureDeviceInput.FromDevice(camera);
        Session.AddInput(input);

        //Add the metadata output channel
        _metadataOutput = new AVCaptureMetadataOutput RectOfInterest = Bounds;
        var metadataDelegate = new MetadataOutputDelegate();
        var dispatchQueue = new DispatchQueue("scannerQueue");
        _metadataOutput.SetDelegate(metadataDelegate, dispatchQueue);
        Session.AddOutput(_metadataOutput);

        _layer = new AVCaptureVideoPreviewLayer(Session)
        
            MasksToBounds = true,
            VideoGravity = AVLayerVideoGravity.ResizeAspectFill,
            Frame = Bounds
        ;

        Layer.AddSublayer(_layer);

        // Hand event over to subscriber
        metadataDelegate.MetadataFound += (s, e) => MetadataFound(s, e);
    

    public override void LayoutSubviews()
    
        base.LayoutSubviews();
        _layer.Frame = Bounds;
        _metadataOutput.RectOfInterest = Bounds;
    

    public void SetMetadataType(AVMetadataObjectType type)
    
        //Confusing! *After* adding to session, tell output what to recognize...
        _metadataOutput.MetadataObjectTypes = type;
    

在我的 LoginView 中,我执行以下操作:

    public override void ViewWillAppear(bool animated)
    
        base.ViewWillAppear(animated);
        // Manipulate navigation stack
        NavigationController.SetViewControllers(
            NavigationController.ViewControllers.Where(
                viewController => viewController is LoginView).ToArray(), false);

        ScannerView.MetadataFound += (s, e) =>
        
            Console.WriteLine($"Found: [e.Type.ToString()] e.StringValue");
            LoginViewModel.BarCode = e.StringValue;
            if (LoginViewModel.DoneCommand.CanExecute())
            
                ScannerView.Session.StopRunning();
                LoginViewModel.DoneCommand.Execute();
            
        ;
    

    public override void ViewDidAppear(bool animated)
    
        base.ViewDidAppear(animated);
        ScannerView.Session.StartRunning();
        ScannerView.SetMetadataType(AVMetadataObjectType.QRCode | AVMetadataObjectType.EAN13Code);
    

有趣的是,一旦我使用手动输入登录并再次注销,这就会起作用,所以我再次在同一个屏幕上(可能不一样,但它的一个新实例,因为 GC 可能会破坏视图因为它已从导航堆栈中删除?)

我已将扫描仪视图作为子视图放在情节提要的 LoginView 上。对于导航,我使用 MVVMCross。 (仅供参考)

那么:我做错了什么?我需要做什么才能使其在第一次加载时工作? (我曾经这样做过 - 使用相同的代码......也许这是一个时间问题?)

【问题讨论】:

【参考方案1】:

显然这是一个时间问题。 我通过添加“点击扫描”范例解决了这个问题。 点击时我执行以下代码:

        public override void TouchesBegan(NSSet touches, UIEvent evt)
    
        base.TouchesBegan(touches, evt);
        Console.WriteLine($"Current types to scan: this.MetadataOutput.MetadataObjectTypes");
        this.SetMetadataType(this.MetadataObjectType);
        Console.WriteLine($"New types to scan: this.MetadataOutput.MetadataObjectTypes");
    

    public void SetMetadataType(AVMetadataObjectType type)
    
        //Confusing! *After* adding to session, tell output what to recognize...
        this.Session.BeginConfiguration();
        this.MetadataOutput.MetadataObjectTypes = type;
        this.Session.CommitConfiguration();
    

MetadataObjectType 设置为我们之前要查找的代码。 这解决了问题——扫描现在每次都有效。 我认为神奇的部分是 Begin- 和 CommitConfiguration 调用,因为如果我不使用触摸扫描范例,这也可以工作。

【讨论】:

以上是关于iOS:相机在第一次加载视图控制器时无法识别二维码的主要内容,如果未能解决你的问题,请参考以下文章

iOS:控制访问相机胶卷新出现

无法识别滑动手势

iOS - 添加约束后无法识别触摸

我的简单相机应用程序(android)在第一次尝试后不会加载相机视图

有关iOS系统中调用相机设备实现二维码扫描功能的注意点(3/3)

IOS Collection 视图单元格第一次单击并在视图出现时删除选择