如何为 ZXing 扫描仪创建和实现 Android CustomOverlay?
How to create and implement a Android CustomOverlay for ZXing Scanner?
我正在为我的 Xamarin.Forms 项目使用 ZXing 条码扫描器插件。根据一些帖子,我需要为 ZXing 扫描仪使用自定义覆盖,以便取消按钮。但是我不熟悉 Android 项目中的 Xamarin.Forms 开发。
到目前为止,我知道一个扫描仪(ZXing 插件的 MobileBarcodeScanner)接受 Android.Views.View 作为覆盖层来替换默认的扫描页面视图。
public async Task<string> ScanAsync()
{
MobileBarcodeScanner scanner = new MobileBarcodeScanner();
scanner.UseCustomOverlay = true;
scanner.CustomOverlay = ???????;
var scanResult = await scanner.Scan();
if (scanResult != null)
{ return scanResult.Text; }
return null;
}
但我不知道如何创建视图页面(在 XML 设计中或以编程方式)并将其设置为 scanner.CustomOverlay。
我不确定是否可以将常见的 Android 视图用于扫描仪,任何详细的参考都将非常有用。
谢谢。
如果要自定义叠加层,必须为每个平台创建自己的视图。您可以像这样自定义叠加层(创建一个名为 ZxingOverlayView
的自定义叠加层,将其设置为 scanner.CustomOverlay
):
var scanner = new ZXing.MobileMobileBarcodeScanner();
scanner.UseCustomOverlay = true;
myCustomOverlayInstance = new ZxingOverlayView(this, scanner);
scanner.CustomOverlay = myCustomOverlayInstance;
ZxingOverlayView
应该继承 view
然后将您的控件添加到自定义视图。
您可以查看有关此 link.
的详细信息
http://slackshotindustries.blogspot.com/2013/04/creating-custom-overlays-in-xzing.html
编辑
步骤齐全
首先,你可以创建一个依赖服务的接口。
public interface IDeviceService
{
Task<string> ScanAsync();
}
您可以在PCL代码中使用此接口。
private async void DependencyButton_Clicked(object sender, EventArgs e)
{
var result = await DependencyService.Get<IDeviceService>().ScanAsync();
if (!string.IsNullOrEmpty(result))
{
await DisplayAlert(result, null, "OK");
}
}
在android平台。你可以设计你的布局。首先,创建一个布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imgClose"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/close"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"/>
<RelativeLayout
android:id="@+id/llScan"
android:layout_width="240dp"
android:layout_height="240dp"
android:layout_centerInParent="true"
android:background="@drawable/scan">
<ImageView
android:id="@+id/imgLine"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/scan_line"
android:layout_centerHorizontal="true" />
</RelativeLayout>
<View
android:id="@+id/viewTop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/llScan"
android:background="@color/title_black"/>
<View
android:id="@+id/viewBottom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/llScan"
android:background="@color/title_black"
android:layout_alignParentBottom="true"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/viewTop"
android:layout_toLeftOf="@id/llScan"
android:layout_above="@id/viewBottom"
android:background="@color/title_black"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/viewTop"
android:layout_above="@id/viewBottom"
android:layout_toRightOf="@id/llScan"
android:background="@color/title_black"/>
</RelativeLayout>
然后实现依赖服务接口,使用你的新布局。
[assembly: Xamarin.Forms.Dependency(typeof(DeviceService))]
namespace Sample.Droid
{
public class DeviceService : IDeviceService
{
public async Task<string> ScanAsync()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner
{
UseCustomOverlay = true
};
//scanner.CustomOverlay = new CustomScanView(Application.Context);
var options = new ZXing.Mobile.MobileBarcodeScanningOptions()
{
TryHarder = true,
AutoRotate = false,
UseFrontCameraIfAvailable = false,
CameraResolutionSelector = new CameraResolutionSelectorDelegate(SelectLowestResolutionMatchingDisplayAspectRatio),
PossibleFormats = new List<ZXing.BarcodeFormat>()
{
ZXing.BarcodeFormat.QR_CODE
}
};
View scanView = LayoutInflater.From(Application.Context).Inflate(Resource.Layout.ScanView, null);
ImageView imgLine = scanView.FindViewById<ImageView>(Resource.Id.imgLine);
ImageView imgClose = scanView.FindViewById<ImageView>(Resource.Id.imgClose);
imgClose.Click += delegate
{
scanner.Cancel();
};
scanner.CustomOverlay = scanView;
ObjectAnimator objectAnimator = ObjectAnimator.OfFloat(imgLine, "Y", 0, DpToPixels(240));
objectAnimator.SetDuration(2500);
objectAnimator.RepeatCount = -1;
objectAnimator.SetInterpolator(new LinearInterpolator());
objectAnimator.RepeatMode = ValueAnimatorRepeatMode.Restart;
objectAnimator.Start();
ZXing.Result scanResults = await scanner.Scan(CrossCurrentActivity.Current.Activity, options);
if (scanResults != null)
{
return scanResults.Text;
}
return string.Empty;
}
private int DpToPixels(double dp)
{
return (int)(dp * Application.Context.Resources.DisplayMetrics.Density);
}
private CameraResolution SelectLowestResolutionMatchingDisplayAspectRatio(List<CameraResolution> availableResolutions)
{
CameraResolution result = null;
//a tolerance of 0.1 should not be visible to the user
double aspectTolerance = 0.1;
var displayOrientationHeight = DeviceDisplay.MainDisplayInfo.Orientation == DisplayOrientation.Portrait ? DeviceDisplay.MainDisplayInfo.Height : DeviceDisplay.MainDisplayInfo.Width;
var displayOrientationWidth = DeviceDisplay.MainDisplayInfo.Orientation == DisplayOrientation.Portrait ? DeviceDisplay.MainDisplayInfo.Width : DeviceDisplay.MainDisplayInfo.Height;
//calculatiing our targetRatio
var targetRatio = displayOrientationHeight / displayOrientationWidth;
var targetHeight = displayOrientationHeight;
var minDiff = double.MaxValue;
//camera API lists all available resolutions from highest to lowest, perfect for us
//making use of this sorting, following code runs some comparisons to select the lowest resolution that matches the screen aspect ratio and lies within tolerance
//selecting the lowest makes Qr detection actual faster most of the time
foreach (var r in availableResolutions.Where(r => Math.Abs(((double)r.Width / r.Height) - targetRatio) < aspectTolerance))
{
//slowly going down the list to the lowest matching solution with the correct aspect ratio
if (Math.Abs(r.Height - targetHeight) < minDiff)
minDiff = Math.Abs(r.Height - targetHeight);
result = r;
}
return result;
}
}
}
IOS代码。
[assembly: Xamarin.Forms.Dependency(typeof(DeviceService))]
namespace Sample.iOS
{
public class DeviceService : IDeviceService
{
public async Task<string> ScanAsync()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner()
{
UseCustomOverlay = true
};
var options = new ZXing.Mobile.MobileBarcodeScanningOptions()
{
TryHarder = true,
AutoRotate = false,
UseFrontCameraIfAvailable = false,
PossibleFormats = new List<ZXing.BarcodeFormat>()
{
ZXing.BarcodeFormat.QR_CODE
}
};
ScannerOverlayView customOverlay = new ScannerOverlayView();
customOverlay.OnCancel += () =>
{
scanner?.Cancel();
};
customOverlay.OnResume += () =>
{
scanner?.ResumeAnalysis();
};
customOverlay.OnPause += () =>
{
scanner?.PauseAnalysis();
};
scanner.CustomOverlay = customOverlay;
ZXing.Result scanResults = null;
scanResults = await scanner.Scan(options);
//customOverlay.Dispose();
if (scanResults != null)
{
return scanResults.Text;
}
return string.Empty;
}
}
这是运行 GIF。
这是一个很好的简单代码。你可以参考它。
https://github.com/Wenfengcheng/ZXing.Sample_Xamarin
我正在为我的 Xamarin.Forms 项目使用 ZXing 条码扫描器插件。根据一些帖子,我需要为 ZXing 扫描仪使用自定义覆盖,以便取消按钮。但是我不熟悉 Android 项目中的 Xamarin.Forms 开发。
到目前为止,我知道一个扫描仪(ZXing 插件的 MobileBarcodeScanner)接受 Android.Views.View 作为覆盖层来替换默认的扫描页面视图。
public async Task<string> ScanAsync()
{
MobileBarcodeScanner scanner = new MobileBarcodeScanner();
scanner.UseCustomOverlay = true;
scanner.CustomOverlay = ???????;
var scanResult = await scanner.Scan();
if (scanResult != null)
{ return scanResult.Text; }
return null;
}
但我不知道如何创建视图页面(在 XML 设计中或以编程方式)并将其设置为 scanner.CustomOverlay。
我不确定是否可以将常见的 Android 视图用于扫描仪,任何详细的参考都将非常有用。
谢谢。
如果要自定义叠加层,必须为每个平台创建自己的视图。您可以像这样自定义叠加层(创建一个名为 ZxingOverlayView
的自定义叠加层,将其设置为 scanner.CustomOverlay
):
var scanner = new ZXing.MobileMobileBarcodeScanner();
scanner.UseCustomOverlay = true;
myCustomOverlayInstance = new ZxingOverlayView(this, scanner);
scanner.CustomOverlay = myCustomOverlayInstance;
ZxingOverlayView
应该继承 view
然后将您的控件添加到自定义视图。
您可以查看有关此 link.
http://slackshotindustries.blogspot.com/2013/04/creating-custom-overlays-in-xzing.html
编辑
步骤齐全
首先,你可以创建一个依赖服务的接口。
public interface IDeviceService
{
Task<string> ScanAsync();
}
您可以在PCL代码中使用此接口。
private async void DependencyButton_Clicked(object sender, EventArgs e)
{
var result = await DependencyService.Get<IDeviceService>().ScanAsync();
if (!string.IsNullOrEmpty(result))
{
await DisplayAlert(result, null, "OK");
}
}
在android平台。你可以设计你的布局。首先,创建一个布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imgClose"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/close"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"/>
<RelativeLayout
android:id="@+id/llScan"
android:layout_width="240dp"
android:layout_height="240dp"
android:layout_centerInParent="true"
android:background="@drawable/scan">
<ImageView
android:id="@+id/imgLine"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/scan_line"
android:layout_centerHorizontal="true" />
</RelativeLayout>
<View
android:id="@+id/viewTop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/llScan"
android:background="@color/title_black"/>
<View
android:id="@+id/viewBottom"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/llScan"
android:background="@color/title_black"
android:layout_alignParentBottom="true"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/viewTop"
android:layout_toLeftOf="@id/llScan"
android:layout_above="@id/viewBottom"
android:background="@color/title_black"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/viewTop"
android:layout_above="@id/viewBottom"
android:layout_toRightOf="@id/llScan"
android:background="@color/title_black"/>
</RelativeLayout>
然后实现依赖服务接口,使用你的新布局。
[assembly: Xamarin.Forms.Dependency(typeof(DeviceService))]
namespace Sample.Droid
{
public class DeviceService : IDeviceService
{
public async Task<string> ScanAsync()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner
{
UseCustomOverlay = true
};
//scanner.CustomOverlay = new CustomScanView(Application.Context);
var options = new ZXing.Mobile.MobileBarcodeScanningOptions()
{
TryHarder = true,
AutoRotate = false,
UseFrontCameraIfAvailable = false,
CameraResolutionSelector = new CameraResolutionSelectorDelegate(SelectLowestResolutionMatchingDisplayAspectRatio),
PossibleFormats = new List<ZXing.BarcodeFormat>()
{
ZXing.BarcodeFormat.QR_CODE
}
};
View scanView = LayoutInflater.From(Application.Context).Inflate(Resource.Layout.ScanView, null);
ImageView imgLine = scanView.FindViewById<ImageView>(Resource.Id.imgLine);
ImageView imgClose = scanView.FindViewById<ImageView>(Resource.Id.imgClose);
imgClose.Click += delegate
{
scanner.Cancel();
};
scanner.CustomOverlay = scanView;
ObjectAnimator objectAnimator = ObjectAnimator.OfFloat(imgLine, "Y", 0, DpToPixels(240));
objectAnimator.SetDuration(2500);
objectAnimator.RepeatCount = -1;
objectAnimator.SetInterpolator(new LinearInterpolator());
objectAnimator.RepeatMode = ValueAnimatorRepeatMode.Restart;
objectAnimator.Start();
ZXing.Result scanResults = await scanner.Scan(CrossCurrentActivity.Current.Activity, options);
if (scanResults != null)
{
return scanResults.Text;
}
return string.Empty;
}
private int DpToPixels(double dp)
{
return (int)(dp * Application.Context.Resources.DisplayMetrics.Density);
}
private CameraResolution SelectLowestResolutionMatchingDisplayAspectRatio(List<CameraResolution> availableResolutions)
{
CameraResolution result = null;
//a tolerance of 0.1 should not be visible to the user
double aspectTolerance = 0.1;
var displayOrientationHeight = DeviceDisplay.MainDisplayInfo.Orientation == DisplayOrientation.Portrait ? DeviceDisplay.MainDisplayInfo.Height : DeviceDisplay.MainDisplayInfo.Width;
var displayOrientationWidth = DeviceDisplay.MainDisplayInfo.Orientation == DisplayOrientation.Portrait ? DeviceDisplay.MainDisplayInfo.Width : DeviceDisplay.MainDisplayInfo.Height;
//calculatiing our targetRatio
var targetRatio = displayOrientationHeight / displayOrientationWidth;
var targetHeight = displayOrientationHeight;
var minDiff = double.MaxValue;
//camera API lists all available resolutions from highest to lowest, perfect for us
//making use of this sorting, following code runs some comparisons to select the lowest resolution that matches the screen aspect ratio and lies within tolerance
//selecting the lowest makes Qr detection actual faster most of the time
foreach (var r in availableResolutions.Where(r => Math.Abs(((double)r.Width / r.Height) - targetRatio) < aspectTolerance))
{
//slowly going down the list to the lowest matching solution with the correct aspect ratio
if (Math.Abs(r.Height - targetHeight) < minDiff)
minDiff = Math.Abs(r.Height - targetHeight);
result = r;
}
return result;
}
}
}
IOS代码。
[assembly: Xamarin.Forms.Dependency(typeof(DeviceService))]
namespace Sample.iOS
{
public class DeviceService : IDeviceService
{
public async Task<string> ScanAsync()
{
var scanner = new ZXing.Mobile.MobileBarcodeScanner()
{
UseCustomOverlay = true
};
var options = new ZXing.Mobile.MobileBarcodeScanningOptions()
{
TryHarder = true,
AutoRotate = false,
UseFrontCameraIfAvailable = false,
PossibleFormats = new List<ZXing.BarcodeFormat>()
{
ZXing.BarcodeFormat.QR_CODE
}
};
ScannerOverlayView customOverlay = new ScannerOverlayView();
customOverlay.OnCancel += () =>
{
scanner?.Cancel();
};
customOverlay.OnResume += () =>
{
scanner?.ResumeAnalysis();
};
customOverlay.OnPause += () =>
{
scanner?.PauseAnalysis();
};
scanner.CustomOverlay = customOverlay;
ZXing.Result scanResults = null;
scanResults = await scanner.Scan(options);
//customOverlay.Dispose();
if (scanResults != null)
{
return scanResults.Text;
}
return string.Empty;
}
}
这是运行 GIF。
这是一个很好的简单代码。你可以参考它。 https://github.com/Wenfengcheng/ZXing.Sample_Xamarin