【问题标题】:xamarin xzing barcode scanner re-scanxamarin zxing 条码扫描仪重新扫描
【发布时间】:2023-04-11 15:15:01
【问题描述】:

我在 xamarin android 表单中使用 zxing 条码扫描仪,我可以让它扫描一个条码没有问题,但我希望能够丢弃他们进行的扫描并能够进行另一次扫描.

我也在使用 MVVM。这是我的 xaml...

 <Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
          
            <forms:ZXingScannerView  x:Name="zxingView" 
                                     IsTorchOn="{Binding TorchON}"       
                                     IsScanning="{Binding IsScanning}" 
                                     IsAnalyzing="{Binding IsAnalyzing}"
                                     Result="{Binding Result, Mode=TwoWay}" 
                                     ScanResultCommand="{Binding ScanCommand}"
                                     />
            <forms:ZXingDefaultOverlay               
                x:Name="scannerOverlay"                                                       
                BottomText="Place the red line over the barcode you'd like to scan." />
            <Button Grid.Row="1" Text="Toggle Flash"  Command="{Binding FlashToggleCommand}"></Button>
        </Grid>

这是我的页面模型

private string barcode = string.Empty;

    public string Barcode
    {
        get { return barcode; }
        set { barcode = value; }
    }

    private bool _isAnalyzing = true;

    public bool IsAnalyzing
    {
        get { return _isAnalyzing; }
        set
        {
            if (!Equals(_isAnalyzing, value))
            {
                _isAnalyzing = value;
                OnPropertyChanged("IsAnalyzing");
            }
        }
    }

    private bool _isScanning = true;
    private bool _torchON = false;
    private DynamicContainerPageModel _hhtScreen;
    private readonly IDeviceManager _deviceManager;

    public ScanningViewPageModel(IDeviceManager deviceManager)
    {
        _deviceManager = deviceManager;
    }

    public override void Init(object initData)
    {
        base.Init(initData);
        _hhtScreen = initData as DynamicContainerPageModel;

    }


    public bool IsScanning
    {
        get { return _isScanning; }
        set
        {
            if (!Equals(_isScanning, value))
            {
                _isScanning = value;
                OnPropertyChanged("IsScanning");
            }
        }
    }

    public bool TorchON
    {
        set
        {
            if (_torchON != value)
            {
                _torchON = value;
                OnPropertyChanged("TorchON");
            }
        }
        get { return _torchON; }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public Command ScanCommand
    {
        get
        {
            return new Command(() =>

            {
                IsAnalyzing = false;
                IsScanning = false;

                Device.BeginInvokeOnMainThread(async () =>
                {
                    Barcode = Result.Text;
                    var response = await CoreMethods.DisplayAlert("Barcode found", "Found: " + Result.Text, "Keep",
                        "Scan Again");

                    if (response)
                    {
                        //Save the value into the model
                        _deviceManager.BeginInvokeOnMainThread(() =>
                                    {
                                        _hhtScreen.SelectedControl.Text = barcode;
                                    });

                        //close page
                        await this.CoreMethods.PopPageModel(false);
                    }
                    else
                    {
                        Result = null;
                        IsAnalyzing = true;
                        IsScanning = true;
                    }
                });

                IsAnalyzing = true;
                IsScanning = true;
            });
        }
    }

    public Command FlashToggleCommand
    {
        get { return new Command(async () => { TorchON = !TorchON; }); }
    }

    public Result Result { get; set; }

当我在弹出窗口中再次按下扫描时,我发现扫描摄像头是否再次激活有点过时,大部分时间它只是冻结。难道我做错了什么?有没有更好的方法让控件重新扫描?

【问题讨论】:

    标签: xamarin xamarin.android zxing freshmvvm


    【解决方案1】:

    我过去遇到过一个非常相似的问题。我最终要做的是在后面的代码中定义扫描仪视图,然后根据需要有条件地从视图中添加/删除。 这就是我最终的样子:

    XAML:

        <!--
            The barcode scanner grid. The actual barcode scanner is
            created and added to the grid in the code behind class.
        -->
        <Grid x:Name="ScannerViewGrid"
              Grid.Row="3"
              HorizontalOptions="FillAndExpand"
              IsVisible="{Binding IsBarcodeScannerRunning}"
              VerticalOptions="FillAndExpand" />
    

    背后的代码:

    private ZXingDefaultOverlay scannerOverlay;
    private ZXingScannerView scannerView;
    
    private void CreateNewScannerView()
    {
        var vm = BindingContext.DataContext as SearchViewModel;
    
        ScannerViewGrid.Children.Clear();
    
        scannerOverlay = null;
        scannerView = null;
    
        scannerOverlay = new ZXingDefaultOverlay();
        scannerOverlay.ShowFlashButton = false;
    
        scannerView = new ZXingScannerView();
        scannerView.SetBinding(ZXingScannerView.ResultProperty, nameof(vm.BarcodeScanResult), BindingMode.OneWayToSource);
        scannerView.SetBinding(ZXingScannerView.ScanResultCommandProperty, nameof(vm.BarcodeScanResultCommand));
        scannerView.IsScanning = true;
    
        ScannerViewGrid.Children.Add(scannerView);
        ScannerViewGrid.Children.Add(scannerOverlay);
    }
    
    private void RemoveScannerView()
    {
        ScannerViewGrid.Children.Clear();
    
        scannerView.IsScanning = false;
        scannerView.IsAnalyzing = false;
        scannerView.RemoveBinding(ZXingScannerView.ResultProperty);
        scannerView.RemoveBinding(ZXingScannerView.ScanResultCommandProperty);
    
        scannerView = null;
        scannerOverlay = null;
    }
    

    【讨论】:

      【解决方案2】:

      我如何解决这个问题:

      Xaml

      <coreControls:ContainerLayout.Content>
                  <Grid>
                      <ContentView
                          x:Name="contentViewCamera"/>
                      <coreControls:SvgImage
                          SvgSource="img_qr_background"
                          VerticalOptions="FillAndExpand"
                          Aspect="AspectFill"/>
                      <Grid
                          x:Name="mainLayout"
                          RowDefinitions="48,*,*,*">
                          <contentViews:HeaderView Title="Canjear cupon"
                                                   TitleColor="{AppThemeBinding Light={StaticResource LightWhiteColor}, Dark={StaticResource DarkWhiteColor}}"
                                                   RightIconSvg="ic_flash_w"
                                                   Margin="6,0" />
                          <material:MaterialEntry
                              Grid.Row="3"
                              HorizontalOptions="Center"
                              VerticalOptions="Center"
                              WidthRequest="240"
                              HeightRequest="42"
                              BackgroundColor="#70000000"
                              BorderColor="#70000000"
                              Placeholder="Ingresa el codigo"/>
                      </Grid>
                  </Grid>
              </coreControls:ContainerLayout.Content>
      

      背后的代码

      public partial class RedeemCouponPage
      {
          private ZXingScannerView _scannerView;
      
          public RedeemCouponPage()
          {
              InitializeComponent();
          }
          protected override void OnAppearing()
          {
              base.OnAppearing();
      
              //mainLayout.Padding = PageHelper.GetPageSafeArea(new Thickness(0, 20), this);
          }
          protected override void OnViewModelSet()
          {
              base.OnViewModelSet();
              var options = new MobileBarcodeScanningOptions
              {
                  AutoRotate = false,
                  TryHarder = true,
                  TryInverted = true,
                  DelayBetweenAnalyzingFrames = 5,
                  DelayBetweenContinuousScans = 5,
                  PossibleFormats = new List<BarcodeFormat>() { BarcodeFormat.QR_CODE }
              };
      
              ViewModel.InitializeCameraCommand = new MvxCommand(() =>
              {
                  _scannerView = new ZXingScannerView()
                  {
                      Options = options,
                      ScanResultCommand = ViewModel.ScanResultCommand
                  };
      
                  _scannerView.SetBinding(ZXingScannerView.IsScanningProperty, nameof(ViewModel.IsBusy));
                  _scannerView.SetBinding(ZXingScannerView.IsAnalyzingProperty, nameof(ViewModel.IsBusy));
                  _scannerView.SetBinding(ZXingScannerView.IsTorchOnProperty, nameof(ViewModel.IsFlashActive));
                  _scannerView.SetBinding(ZXingScannerView.ResultProperty, nameof(ViewModel.Result), BindingMode.TwoWay);
                  contentViewCamera.Content = _scannerView;
              });
          }
      }
      

      视图模型

      public class RedeemCouponViewModel: BaseViewModel
      {
          private readonly ICouponService CouponService = Mvx.IoCProvider.Resolve<ICouponService>();
      
          public IMvxCommand InitializeCameraCommand { get; set; }
      
          private ZXing.Result _result;
          public ZXing.Result Result
          {
              get => _result;
              set
              {
                  SetProperty(ref _result, value);
                  BarCodeText = value.Text;
              }
          }
      
          private bool _isFlashActive;
          public bool IsFlashActive
          {
              get => _isFlashActive;
              set => SetProperty(ref _isFlashActive, value);
          }
      
          private string _barCodeText;
          public string BarCodeText
          {
              get => _barCodeText;
              set => SetProperty(ref _barCodeText, value);
          }
      
          private Coupon _coupon;
          public Coupon Coupon
          {
              get => _coupon;
              set => SetProperty(ref _coupon, value);
          }
      
          public override void ViewAppeared()
          {
              base.ViewAppeared();
      
              if (DeviceInfo.DeviceType == DeviceType.Physical)
                  InitializeCameraCommand.Execute();
      
              IsBusy = true;
          }
      
          public IMvxAsyncCommand ScanResultCommand => new MvxAsyncCommand(async () =>
          {
              if (Result == null)
              {
                  IsBusy = true;
                  return;
              }
              else
                  IsBusy = false;
      
              Coupon = await CouponService.Get(BarCodeText);
              PopupIsVisible = true;
      
      
          }, () => IsBusy);
      
          public IMvxCommand ConfirmRedeemCommand => new MvxCommand(()=>
          {
              DisplaySuccessView("Canjeado!","El cupon ha sido canjeado con exito.");
              if (DeviceInfo.DeviceType == DeviceType.Physical)
                  InitializeCameraCommand.Execute();
              PopupIsVisible = false;
              IsBusy = true;
          });
      
          public IMvxCommand BackToScanerCommand => new MvxCommand(() =>
          {
              PopupIsVisible = false;
              if (DeviceInfo.DeviceType == DeviceType.Physical)
                  InitializeCameraCommand.Execute();
      
              IsBusy = true;
          });
      }
      

      【讨论】: