上篇文章地址:
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了..