C#開發移動應用系列(3.使用照相機掃描二維碼+各種基礎知識)


前言

上篇文章地址:

C#開發移動應用系列(1.環境搭建)

C#開發移動應用系列(2.使用WebView搭建WebApp應用)

今天我們來講一下如何使用Camera來調用照相機掃描二維碼.

(Tips:大神別問我為什么不用Camera2,飯要一口口吃..慢慢來.....................其實是我還沒看懂..)

確定一下本篇的學習目標:

1.學會如何調用Camera來實現照相機預覽

2.學會如何跳轉Activity並傳值

3.學會如何識別相機預覽中的二維碼,並讀取

效果圖:

 

 

 

正文

1.學會如何調用Camera來實現照相機預覽

   我們先來看看如何使用Camera來實現照相機預覽..

   我們首先新建一個Activity,...嗯..暫且命名為SaoYiSaoActivity (不是騷..是掃..)

   在Resources\layout 創建對應的界面,SaoYiSao.axml

   在SaoYiSaoActivity的OnCreate中加載這個頁面,代碼如下:

   

protected override void OnCreate(Bundle savedInstanceState)
{
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.SaoYiSao);
          
}

在SaoYiSao.axml中拖入控件SurfaceView,這里的SurfaceView是用來展示預覽畫面的..(具體的SurfaceView作用自行百度..或者等我下篇..)

同樣,我們把它鋪滿全屏,如圖:

下面我們開始寫代碼...

因為我們要調用照相機和監控SurfaceView.所以我們的SaoYiSaoActivity 需要繼承一些東西,代碼如下:

public class SaoYiSaoActivity : Activity,Android.Hardware.Camera.IPreviewCallback,ISurfaceHolderCallback

需要繼承Android.Hardware.Camera.IPreviewCallback來獲取照相機的預覽回調

需要繼承ISurfaceHolderCallback來獲取SurfaceView發生在表面的事件和變化

我們實現這兩個接口,會得到如下幾個方法

OnPreviewFrame(),來自於Android.Hardware.Camera.IPreviewCallback

SurfaceChanged()

SurfaceCreated()

SurfaceDestroyed()

我們一個一個來實現,

不過在此之前,先回到OnCreate()方法中,初始化一下我們的SurfaceView

編寫代碼如下:

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.SaoYiSao);
            //獲取surfaceView1
            var surface = FindViewById<SurfaceView>(Resource.Id.surfaceView1);
            //獲取surface的線程
            var holder = surface.Holder;
            //設置線程回調為本類
            holder.AddCallback(this);
            //表明該Surface不包含原生數據
            holder.SetType(Android.Views.SurfaceType.PushBuffers);
            //設置這個Surface的大小
            holder.SetFixedSize(300, 200);
        }

解釋都在注釋里了..我就不多說了..

下面開始實現剛才的接口..

首先來實現 SurfaceCreated(),代碼如下(注:這里是重點):

 1        public void SurfaceCreated(ISurfaceHolder holder)
 2         {
 3             camera = Android.Hardware.Camera.Open();
 4             Android.Hardware.Camera.Parameters p = camera.GetParameters();
 5             p.PictureFormat = ImageFormatType.Jpeg;
 6             camera.SetParameters(p);
 7             camera.SetPreviewCallback(this);
 8             camera.SetPreviewDisplay(holder);
 9             camera.StartPreview();
10 
11 
12         }

講一下這些代碼做了什么,首先很明顯..打開照相機.第二句,獲取照相機的參數,設置圖片類型為Jpeg.重新把參數賦值給照相機.

設置照相機的預覽回調為自身類,設置照相機顯示為SurfaceView的線程

最后,開始預覽.

 

然后我們實現SurfaceDestroyed(),這里是當Surface被銷毀之前調用的方法,代碼如下(注:也很重要):

public void SurfaceDestroyed(ISurfaceHolder holder)
        {
            //刪除回調
            holder.RemoveCallback(this);
            //刪除照相機回調
            camera.SetPreviewCallback(null);
            //停止照相機預覽
            camera.StopPreview();
            //釋放照相機
            camera.Release();
            camera = null;
        }

一定要寫這些,不然照相機會一直處於占用狀態..然后GG..

實現上面兩個方法.其實我們就可以調用照相機預覽了...

OnPreviewFrame()這個方法,我們暫時先不實現 放個空的.打個斷點

運行,我們會發現.OnPreviewFrame()這個方法會被不停的調用.

里面有兩個參數

 

 public void OnPreviewFrame(byte[] data, Android.Hardware.Camera camera)

很明顯,這個字節類型的data就是每次照相機預覽傳回來的當前幀的圖片信息.

camera當然就是照相機了..

所以我們就可以從這里一直獲取預覽的圖片幀..(不要心急,慢慢來)

我們進入第二個知識點

2.學會如何跳轉Activity並傳值

我們知道,安卓的每一個界面轉換都是由一個或者多個Activity實現的..

前面我們也單獨寫了一個SaoYiSaoActivity

那么我們該如何跳轉過去呢..往下看..

我們在MainActivity添加一個Button,給他添加一個點擊事件,代碼如下:

 

btn2.Click += delegate
                {
                    Intent intent = new Intent(this,typeof(SaoYiSaoActivity));
                    intent.AddFlags(ActivityFlags.SingleTop);
                    StartActivityForResult(intent, 1);
                };

用SaoYiSaoActivity類型申明一個Intent ,

然后添加Activity啟動模式,為SingleTop.

因為我們要獲取SaoYiSaoActivity傳遞回來的參數,所以我們采用StartActivityForResult來跳轉.

第一個參數當然就是要跳轉的Intent ,第二個是獲取返回值用的Code編號(注意:要大於0)

這樣我們就實現了跳到SaoYiSaoActivity..

那么如何獲取SaoYiSaoActivity給的返回值呢?.

我們重寫Activity的OnActivityResult方法,如下:

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);

            //如果當初的發的requestCode =1
            if (requestCode == 1 && resultCode == Result.Ok)
            { 
               
                webView.LoadUrl(data.GetStringExtra("code"));
                Toast.MakeText(this, "掃描結果:" + data.GetStringExtra("code"), ToastLength.Short).Show();
            }
        }

大家可以看到,上面我們有一個判斷requestCode==1,這個1就是我們傳遞過去的第二個參數.

當你有多個跳轉界面的時候,就可以用這個requestCode來區分.

這樣,我們就完成了界面的跳轉和獲取返回值

3.學會如何識別相機預覽中的二維碼,並讀取

下面我們講講如何讀取相機中的二維碼.

.Net解析二維碼,在我的知識儲備里面...常用的只有2個庫,一個是QRCode,一個是ZXing.Net.(PS:如果有大神知道更好的,請留言賜教..)

很遺憾QRCode,使用的是GDI+ 也就是System.drawing..很明顯..我們在手機端..調用不到..

所以只能用ZXing.Net

我們在nuget中搜索ZXing.Net.

如圖:

類型很多..而且有各種版本..我們選擇ZXing.Net.Mobile,

當然這里還有個ZXing.Net.Mobile.Forms,這個是封裝好的二維碼掃描控件..本文主要是學習,所以不使用(當然..你主要是實現功能..就用這個..巨人的肩膀上 多刺激..).

我們首先定義一個方法CodeDecoder來專門解析二維碼,代碼如下:

        /// <summary>
        /// 二維碼解碼
        /// </summary>
        /// <returns></returns>
        public string CodeDecoder(byte[] data,int width,int height)
        {

            byte[] bytes = data;//獲取圖片字節
             //設置位圖源
            PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, width, height, 0, 0, width,height, false);
            //處理像素值內容信息
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
             //初始化解析器
            ZXing.Reader reader = new QRCodeReader();
            //解析位圖
            ZXing.Result result = reader.decode(bitmap);
            if (result == null)
                return null;
            return result.Text;//返回解析結果  
        }

 

前面我們說過了.OnPreviewFrame()是照相機預覽的回調.所以我們現在就來實現他.

代碼如下:

 public void OnPreviewFrame(byte[] data, Android.Hardware.Camera camera)
        {

            try
            {
                //獲取相機寬度
                int previewWidth = camera.GetParameters().PreviewSize.Width;
                //獲取相機高度
                int previewHeight = camera.GetParameters().PreviewSize.Height;
                //解析二維碼
                var date = CodeDecoder(data, previewWidth, previewHeight);
                //判斷是否解析到二維碼.
                if (date != null)
                {
                    //跳轉回主頁面
                    Intent intent = new Intent(this, typeof(MainActivity));
                    //放入一個key 為code 的解析后的值
                    intent.PutExtra("code", date);
                    //狀態設為OK
                    SetResult(Android.App.Result.Ok, intent);
                    //關閉當前界面
                    Finish();
                }

            }
            catch (IOException)
            {

               
            }
        }

上面的代碼,if中的代碼就是如何跳轉回主界面,並且傳遞返回值.

 

最后我們用百度的網址,生成一個二維碼,調試,掃描..就是前面的效果圖拉~

 

 

寫在最后

感覺很多東西..其實基本和JAVA都是一樣的..

所以不要抱怨Xamarin的資料少..你能查到相關的JAVA資料..基本也就搞定Xamarin了..


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM