1. 程式人生 > >Xamarin.Android-用ZXing實現二維碼掃描以及連續掃描

Xamarin.Android-用ZXing實現二維碼掃描以及連續掃描

一、前言

本文的內容有兩個基礎:ZXing.Net和ZXing.Net.Mobile

ZXing.Net:ZXing的C#實現,主要封裝了各種二維碼的編碼、解碼等跨平臺的演算法

ZXing.Net.Mobile:對ZXing.Net在xamarin的應用進行了封裝,主要實現了攝像頭掃描、掃描view、掃描activity、掃描Fragment等

二、效果圖

        

三、基本實現

1、彈出新視窗進行掃描

public class MainFragment : Android.Support.V4.App.Fragment
    {
        MobileBarcodeScanner scanner;

        
public override View OnCreateView(LayoutInflater inflater, ViewGroup p1, Bundle p2) { return inflater.Inflate(Resource.Layout.Main, null); } public override void OnViewCreated(View view, Bundle savedInstanceState) { base.OnViewCreated(view, savedInstanceState); scanner
= new MobileBarcodeScanner(this.Activity); this.View.FindViewById<Button>(Resource.Id.btnDefault).Click += btnDefault_Click; this.View.FindViewById<Button>(Resource.Id.btnCustom).Click += btnCustom_Click; } async void btnDefault_Click(object
sender, EventArgs e) { //不使用自定義介面 scanner.UseCustomOverlay = false; //設定上下提示文字 scanner.TopText = "上面的文字"; scanner.BottomText = "下面的文字"; var result = await scanner.Scan(); HandleScanResult(result); } async void btnCustom_Click(object sender, EventArgs e) { View zxingOverlay; //使用自定義介面(可以給框內加個動畫什麼的,這個自由發揮) scanner.UseCustomOverlay = true; zxingOverlay = LayoutInflater.FromContext(this.Activity).Inflate(Resource.Layout.ZxingOverlay, null); scanner.CustomOverlay = zxingOverlay; var result = await scanner.Scan(); HandleScanResult(result); } void HandleScanResult(ZXing.Result result) { string msg = ""; if (result != null && !string.IsNullOrEmpty(result.Text)) msg = "掃描結果: " + result.Text; else msg = "掃描取消!"; this.Activity.RunOnUiThread(() => { Toast.MakeText(this.Activity, msg, ToastLength.Short).Show(); }); } }
View Code

btnDefault_Click中使用了預設的彈出掃描,可定製性差,只能修改上下的文字

btnCustom_Click中使用了自定義介面彈出掃描,其實就是給掃描介面上面覆蓋一層自定義的佈局

在HandleScanResult中進行掃描結果的處理,這裡只是簡單的Toast

2、Fragment中整合掃描

這裡使用了ZXing.Net.Mobile庫中已經封裝好的ZXingScannerFragment,並使用了覆蓋層進行介面自定義

public class ScannerFragment : Android.Support.V4.App.Fragment
    {
        ZXingScannerFragment scanFragment;
        View zxingOverlay;

        public override View OnCreateView(LayoutInflater inflater, ViewGroup p1, Bundle p2)
        {
            return inflater.Inflate(Resource.Layout.Scanner, null);
        }

        public override void OnViewCreated(View view, Bundle savedInstanceState)
        {
            base.OnViewCreated(view, savedInstanceState);

            zxingOverlay = LayoutInflater.FromContext(this.Activity).Inflate(Resource.Layout.ZxingOverlay, null);

            scanFragment = new ZXingScannerFragment(ScanResultCallback);
            scanFragment.UseCustomView = true;
            scanFragment.CustomOverlayView = zxingOverlay;

            this.Activity.SupportFragmentManager.BeginTransaction()
                .Replace(Resource.Id.fragment_container, scanFragment)
                .Commit();
        }

        private void ScanResultCallback(ZXing.Result result)
        {
            if (result == null || string.IsNullOrEmpty(result.Text))
            {
                this.Activity.RunOnUiThread(() =>
                {
                    Toast.MakeText(this.Activity, "掃描已取消!", ToastLength.Short).Show();
                    ((HomeFragment)this.FragmentManager.Fragments[0]).SetCurrentTab("Main");
                });
                return;
            }
            else
            {
                //掃描成功
                this.Activity.RunOnUiThread(() =>
                {
                    //震動
                    Vibrator vibrator = (Vibrator)Application.Context.GetSystemService(Context.VibratorService);
                    long[] pattern = { 0, 350, 220, 350 };
                    vibrator.Vibrate(pattern, -1);

                    Console.WriteLine(result.Text);

                    Toast.MakeText(this.Activity, result.Text, ToastLength.Short).Show();
                    ((HomeFragment)this.FragmentManager.Fragments[0]).SetCurrentTab("Main");
                });
                return;
            }
        }
    }
View Code

初始化ZXingScannerFragment,為其傳入一個Action<ZXing.Result>型別的ScanResultCallback回撥,

在ScanResultCallback中進行掃描結果處理:震動、輸出、Toast、切換Fragment等

四、連續掃描

現在基本能掃描了,不過現在有個需求:掃描後如果掃描結果不是手機號碼則繼續掃描。

OK,修改一下掃描完成後的回撥處理

//此處加上二維碼的格式要求,如果不符合要求,就繼續掃描(我這裡是判斷是否是手機號碼)
                    if (IsTelephone(result.Text))
                    {
                        Toast.MakeText(this.Activity, result.Text, ToastLength.Short).Show();
                        ((HomeFragment)this.FragmentManager.Fragments[0]).SetCurrentTab("Main");
                    }
                    else
                    {
                        Toast.MakeText(this.Activity, "掃描的二維碼格式不正確!", ToastLength.Short).Show();
                    }
/// <summary>
        /// 驗證手機號碼的格式
        /// </summary>
        public bool IsTelephone(string str_telephone)
        {
            return Regex.IsMatch(str_telephone, @"^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$");
        }

本來以為這樣就搞定了,沒想到掃描結果不是手機號時,提示 "掃描的二維碼格式不正確!"後便停止掃描了。

看來ZXing.Net.Mobile庫只要掃描完成後,就會停止掃描(我想作者是為了防止重複掃描的問題吧)。

為了實現連續掃描就只能修改ZXing.Net.Mobile庫了

下面只是“Fragment中整合掃描”中的實現,“彈出新視窗進行掃描”也有類似的問題,小夥伴們自己檢視原始碼發揮吧,哈哈!

經過分析發現ZXingSurfaceView類中的OnPreviewFrame方法在掃描完成後,觸發回撥前,呼叫了ShutdownCamera ();

這便是停止掃描的罪魁禍首,OK,將其抹殺,這時是可以連續掃描了,不過即使掃描結果是手機號掃描還會繼續,這樣就有可能出現重複掃描的問題,

因此這種情況下,掃描結果符合要求後,需要手動“停止掃描”:ZXingScannerFragment.Shutdown()

//此處加上二維碼的格式要求,如果不符合要求,就繼續掃描(我這裡是判斷是否是手機號碼)
                    if (IsTelephone(result.Text))
                    {
                        //主動關閉攝像頭,防止重複掃描
                        scanFragment.Shutdown();

                        Toast.MakeText(this.Activity, result.Text, ToastLength.Short).Show();
                        ((HomeFragment)this.FragmentManager.Fragments[0]).SetCurrentTab("Main");
                    }
                    else
                    {
                        Toast.MakeText(this.Activity, "掃描的二維碼格式不正確!", ToastLength.Short).Show();
                    }

原始碼下載 

參考:

如果你覺得文章對你有幫助,可以點選旁邊的“推薦”按鈕,這樣會讓更多需要的人有機會看到