使用C#和Xamarin开发移动应用:相机二维码扫描基础
本文将介绍如何使用C#和Xamarin调用设备相机扫描二维码,并讲解相关的基础知识,包括相机预览、Activity跳转传值以及二维码的识别与读取。
1. 实现相机预览
首先,我们需要创建一个新的Activity,命名为 SaoYiSaoActivity,并为其准备一个布局文件 SaoYiSao.axml。在布局文件中,添加一个 SurfaceView控件,用于显示相机预览画面。为了让 SurfaceView铺满整个屏幕,可以设置其布局参数。
在 SaoYiSaoActivity 的 OnCreate 方法中,加载布局文件并初始化 SurfaceView:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.SaoYiSao);
var surfaceView = FindViewById<SurfaceView>(Resource.Id.surfaceView1);
var surfaceHolder = surfaceView.Holder;
surfaceHolder.AddCallback(this); // 设置SurfaceHolder的回调为当前Activity
surfaceHolder.SetType(SurfaceType.PushBuffers); // 表示Surface不包含原生数据
surfaceHolder.SetFixedSize(300, 200); // 设置Surface的大小
}
为了处理相机预览和SurfaceView的生命周期事件,SaoYiSaoActivity 需要实现 Android.Hardware.Camera.IPreviewCallback 和 ISurfaceHolderCallback 接口。这些接口提供了 OnPreviewFrame, SurfaceChanged, SurfaceCreated, 和 SurfaceDestroyed 等方法。
实现 SurfaceCreated 方法来初始化相机:
public void SurfaceCreated(ISurfaceHolder holder)
{
camera = Android.Hardware.Camera.Open(); // 打开相机
var parameters = camera.GetParameters();
parameters.PictureFormat = ImageFormatType.Jpeg; // 设置图片格式
camera.SetParameters(parameters); // 应用相机参数
camera.SetPreviewCallback(this); // 设置预览回调
camera.SetPreviewDisplay(holder); // 设置预览Surface
camera.StartPreview(); // 开始预览
}
实现 SurfaceDestroyed 方法来释放相机资源:
public void SurfaceDestroyed(ISurfaceHolder holder)
{
holder.RemoveCallback(this);
camera.SetPreviewCallback(null); // 移除预览回调
camera.StopPreview(); // 停止预览
camera.Release(); // 释放相机
camera = null;
}
OnPreviewFrame(byte[] data, Android.Hardware.Camera camera) 方法会在每一帧预览画面被捕获时调用。data 参数包含了当前帧的图像数据。
2. Activity跳转与传值
为了从主界面跳转到 SaoYiSaoActivity 并接收扫描结果,我们可以在主界面的MainActivity中添加一个按钮,并为其添加点击事件处理:
btnScan.Click += delegate
{
var intent = new Intent(this, typeof(SaoYiSaoActivity));
intent.AddFlags(ActivityFlags.SingleTop); // 设置启动模式
StartActivityForResult(intent, 1); // 启动Activity并设置请求码
};
要接收从 SaoYiSaoActivity 返回的数据,需要重写MainActivity的 OnActivityResult 方法:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == 1 && resultCode == Result.Ok)
{
var qrCodeData = data.GetStringExtra("code");
// 在这里处理获取到的二维码数据,例如加载到WebView
// webView.LoadUrl(qrCodeData);
Toast.MakeText(this, "扫描结果: " + qrCodeData, ToastLength.Short).Show();
}
}
3. 二维码识别与读取
在.NET生态中,常用的二维码解析库是 ZXing.Net。由于在移动端无法直接使用 System.Drawing (GDI+),因此选择 ZXing.Net.Mobile。可以在NuGet包管理器中搜索并安装 ZXing.Net.Mobile。
创建一个 CodeDecoder 方法来解析二维码:
public string CodeDecoder(byte[] data, int width, int height)
{
// 创建YUV格式的源
var source = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height, false);
// 二值化处理
var bitmap = new BinaryBitmap(new HybridBinarizer(source));
// 使用QRCodeReader进行解析
var reader = new QRCodeReader();
var result = reader.decode(bitmap);
return result?.Text; // 返回解析到的文本,如果解析失败则返回null
}
在 SaoYiSaoActivity 的 OnPreviewFrame 方法中调用 CodeDecoder 来识别二维码:
public void OnPreviewFrame(byte[] data, Android.Hardware.Camera camera)
{
try
{
var parameters = camera.GetParameters();
int previewWidth = parameters.PreviewSize.Width;
int previewHeight = parameters.PreviewSize.Height;
var decodedData = CodeDecoder(data, previewWidth, previewHeight);
if (decodedData != null)
{
// 解析成功,跳转回主界面并传递结果
var intent = new Intent(this, typeof(MainActivity));
intent.PutExtra("code", decodedData); // 传递解析结果
SetResult(Result.Ok, intent); // 设置返回结果
Finish(); // 关闭当前Activity
}
}
catch (IOException)
{
// 处理可能的IO异常
}
}
通过以上步骤,即可实现相机二维码扫描功能,并将扫描结果传递回主界面。