zoukankan      html  css  js  c++  java
  • C#开发移动应用系列(3.使用照相机扫描二维码+各种基础知识)

    前言

    上篇文章地址:

    C#开发移动应用系列(1.环境搭建)

    C#开发移动应用系列(2.使用WebView搭建WebApp应用)

    今天我们来讲一下如何使用Camera来调用照相机扫描二维码.

    (Tips:大神别问我为什么不用Camera2,饭要一口口吃..慢慢来.....................其实是我还没看懂..)

    确定一下本篇的学习目标:

    1.学会如何调用Camera来实现照相机预览

    2.学会如何跳转Activity并传值

    3.学会如何识别相机预览中的二维码,并读取

    效果图:

    正文

    1.学会如何调用Camera来实现照相机预览

       我们先来看看如何使用Camera来实现照相机预览..

       我们首先新建一个Activity,...嗯..暂且命名为SaoYiSaoActivity (不是骚..是扫..)

       在Resourceslayout 创建对应的界面,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了..

  • 相关阅读:
    Mime Types
    对MySQL DELETE语法的详细解析
    创建MySQL存储过程示例
    Python安装
    python学习之matplotlib实战
    python学习之numpy实战
    SQLserver建表规则
    机器学习之BP神经网络
    机器学习之决策树算法
    Spring学习总结
  • 原文地址:https://www.cnblogs.com/GuZhenYin/p/7070608.html
Copyright © 2011-2022 走看看