如何在 Xamarin Forms 中翻转 ZXing 使用的相机

How to flip Camera used by ZXing in Xamaring Forms

作为我正在开发的应用程序的一部分,我希望能够在使用前置摄像头或后置摄像头之间进行切换,但根据我的搜索和尝试,我无法使用前置摄像头让它工作。

进行扫描的扫描仪视图是 ZXing.Net.Mobile.Forms 中名为 ZXingScannerView 的视图,在我的 xaml 中这样定义,连同应该进行相机翻转的按钮。

<elements:AdvancedTabbedPage
...
xmlns:elements="clr-namespace:Wolf.Utility.Main.Xamarin.Elements;assembly=Wolf.Utility.Main"
xmlns:forms="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms">
...

<ContentPage>
   <ContentPage.ToolbarItems>
       <ToolbarItem Text="{x:Static resources:AppResources.CameraFlipText}" x:Name="CameraFlipButton" Clicked="CameraFlipButton_OnClicked"/>
   </ContentPage.ToolbarItems>
   <ContentPage.Content>
...
       <forms:ZXingScannerView x:Name="ScannerView" HeightRequest="200" IsAnalyzing="False" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" IsVisible="False" IsScanning="True"/>
...
   </ContentPage.Content>
</ContentPage>

按钮可以在下图的右上角看到,而扫描仪视图只有在扫描打开时才可见,它不在图像上。

Image of the Page where Scannning is happening

单击该按钮应在使用前置摄像头和后置摄像头之间切换,默认使用前置摄像头。然而,点击按钮似乎没有做任何事情,除了然后写入我的日志。按钮的Clicked事件代码如下所示。

...
private void CameraFlipButton_OnClicked(object sender, EventArgs e)
        {
            Logging.Log(LogType.Information, "Flipping Camera...");

            Config.DefaultOptions.UseFrontCameraIfAvailable = !Config.DefaultOptions.UseFrontCameraIfAvailable;
            Config.CustomOptions.UseFrontCameraIfAvailable = !Config.CustomOptions.UseFrontCameraIfAvailable;

            if (!ScanningToggle.IsToggled) return;

            Logging.Log(LogType.Information, "Restarting Scanning...");
            ScanningToggle.IsToggled = false;
            ScanningToggle.IsToggled = true;
        }

上面代码中提到的选项是这样定义的,在我的Config class中。名为 CustomOptions 的其他值在我的 Config class 的 Init 方法中设置,但这些与此问题无关。

public class Config
{
...
public static MobileBarcodeScanningOptions CustomOptions = new MobileBarcodeScanningOptions() { UseFrontCameraIfAvailable = true };
public static MobileBarcodeScanningOptions DefaultOptions = new MobileBarcodeScanningOptions() { UseFrontCameraIfAvailable = true };
...
}

我的扫描仪将使用的选项总是在这两者之间选择,具体取决于设置中的一些用户输入。

试图让它工作我也试过...

  1. 反转值UseFrontCameraIfAvailable,而扫描是运行

  2. 反转用于开始扫描然后重新开始扫描的选项的值 UseFrontCameraIfAvailable - 上面显示的代码。

  3. 将 ZXingScannerView 的 IsScanning 从 true 更改为 false,同时使用更改的选项重新启动扫描,但这只会导致相机冻结。

在我正要提交问题时发现了这个 。明天我将尝试关注那个,但仍然非常喜欢我的意见。

如果我遗漏了一些您认为可能有所帮助的问题,请随意提问,或索取额外的代码。

我觉得Zxing开始扫描后是不能切换前后摄像头的,所以要先选择和设置这个选项

 var options = new MobileBarcodeScanningOptions
 {
     AutoRotate = true,
     UseNativeScanning = true,
     TryHarder = true,
     TryInverted = true,
     UseFrontCameraIfAvailable  = true
 };

 var scannedCode = await _scanner.Scan(options);

我想出了如何成功翻转相机。

  • 为此,我首先从包含它的堆栈中删除 ZXingScannerView。

  • 然后我创建一个新的 ZXingScannerView 实例,复制旧实例的所有设置(布局定位、ZXingScannerView 特定值等)。

  • 然后我将 ZXingScannerView 重新添加到堆栈,从那里对 UseFrontCameraIfAvailable 属性 的任何更改都会生效。

成功的代码如下。首先是复制属性的通用方法,然后是重新创建 ZXingScannerView 的方法,最后是我启用扫描的方法。

public class GenericFactory
    {
        // Assistance with Setter Accessibility: 
        public static T CopyProperties<T>(T newObject, T oldObject, bool ignoreDefaults = true,
            bool skipSelectedProperties = true, params string[] skippedProperties) where T : class
        {
            var type = typeof(T);
            var properties = type.GetProperties();

            foreach (var property in properties)
            {
                if (ignoreDefaults && property.GetValue(oldObject) == default)
                    continue;
                if (skipSelectedProperties && skippedProperties.Contains(property.Name))
                    continue;
                if (!property.CanWrite)
                    continue;

                property.SetValue(newObject, property.GetValue(oldObject));
            }

            return newObject;
        }
    }
private void RecreateScannerView()
        {
            if (Config.DebugMode) Logging.Log(LogType.Debug, $"{nam1eof(RecreateScannerView)} method called");
            ScannerStack.Children.Remove(ScannerView);

            if (Config.DebugMode)
                Logging.Log(LogType.Debug,
                    $"Coping properties from existing {nameof(ZXingScannerView)} into a new {nameof(ZXingScannerView)}");
            ScannerView = GenericFactory.CopyProperties(new ZXingScannerView() {IsScanning = false}, ScannerView,
                skippedProperties: new List<string>() {nameof(ScannerView.IsScanning)}.ToArray());
            ScannerView.OnScanResult += ScannerView_OnScanResult;

            ScannerStack.Children.Add(ScannerView);
        }
private void EnableScan(MobileBarcodeScanningOptions imputedOptions = null)
        {
            if (Config.DebugMode) Logging.Log(LogType.Debug, $"{nameof(EnableScan)} Method is run in Thread named => {Thread.CurrentThread.Name}");

            var chosenOptions = imputedOptions ?? (Config.UseCustomOptions ? Config.CustomOptions : Config.DefaultOptions);
            if (Config.DebugMode)
                Logging.Log(LogType.Information,
                    $"Chose this option for Scanning => {(imputedOptions != null ? nameof(imputedOptions) : (Config.UseCustomOptions ? nameof(Config.CustomOptions) : nameof(Config.DefaultOptions)))}");
            ScannerView.Options = chosenOptions;

            RecreateScannerView();

            Logging.Log(LogType.Information, $"Starting the Scanning...");
            ScannerView.IsScanning = true;
            ScannerView.IsAnalyzing = true;
            ScannerView.IsVisible = true;

            if (Config.DebugMode)
                Logging.Log(LogType.Debug,
                    $"{nameof(EnableScan)} Called and Finished; ScannerView.IsAnalyzing => {ScannerView.IsAnalyzing}; ScannerView.IsVisible => {ScannerView.IsVisible}");
        }

我的翻转UseFrontCameraIfAvailable值的方法就是上面问题中的方法

希望这最终能帮助其他可能遇到同样问题的人。