如何在 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 };
...
}
我的扫描仪将使用的选项总是在这两者之间选择,具体取决于设置中的一些用户输入。
试图让它工作我也试过...
反转值UseFrontCameraIfAvailable,而扫描是运行
反转用于开始扫描然后重新开始扫描的选项的值 UseFrontCameraIfAvailable - 上面显示的代码。
将 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值的方法就是上面问题中的方法
希望这最终能帮助其他可能遇到同样问题的人。
作为我正在开发的应用程序的一部分,我希望能够在使用前置摄像头或后置摄像头之间进行切换,但根据我的搜索和尝试,我无法使用前置摄像头让它工作。
进行扫描的扫描仪视图是 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 };
...
}
我的扫描仪将使用的选项总是在这两者之间选择,具体取决于设置中的一些用户输入。
试图让它工作我也试过...
反转值UseFrontCameraIfAvailable,而扫描是运行
反转用于开始扫描然后重新开始扫描的选项的值 UseFrontCameraIfAvailable - 上面显示的代码。
将 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值的方法就是上面问题中的方法
希望这最终能帮助其他可能遇到同样问题的人。