Android开发实现模仿360二维码扫描功能实例详解
本文实例讲述了android开发实现模仿360二维码扫描功能的方法。分享给大家供大家参考,具体如下:
一、效果图:
二、框架搭建
1、首先,下载最新zxing开源项目。 下载地址:
或 点击此处本站下载。
2、分析项目结构,明确扫描框架需求。在zxing中,有很多其他的功能,项目结构比较复杂;针对二维码qrcode扫描,我们需要几个包:
(1)com.google.zxing.client.android.camera 基于camera调用以及参数配置,核心包
(2)decodeformatmanager、decodethread、decodehandler 基于解码格式、解码线程、解码结果处理的解码类
(3)viewfinderview、viewfinderresultpointcallback 基于取景框视图定义的view类
(4)captureactivity、captureactivityhandler 基于扫描activity以及扫描结果处理的capture类
(5)inactivitytimer、beepmanager、finishlistener 基于休眠、声音、退出的辅助管理类
(6)intents、intentsource、prefrencesactivity 基于常量存储的常量类
3、新建工程,添加如下权限permission:
<uses-permission android:name="android.permission.camera"/> <uses-permission android:name="android.permission.internet" /> <uses-permission android:name="android.permission.vibrate" /> <uses-permission android:name="android.permission.flashlight" />
4、 添加core.jar文件,并buildpath;将上述类或包加入工程后,会报一系列错误,原因有几点:
(1)资源文件缺乏,将zxing下需要的资源文件copy到新工程下
(2)版本兼容问题,zxing下很多技术都是使用4.0版本及以上,集成到低版本之后,须做相应改动,详情参照项目源码
(3)包结构引用问题,需要重新导入包引用
5、最后框架
三、具体实现
1、创建mainactivity用于跳转到扫描页面
/** * 二维码扫描 * @project app_zxing * @package com.android.scan * @author chenlin * @version 1.0 * @date 2014年3月6日 */ public class mainactivity extends activity { private button mbtnscan; private button mbtnback; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); mbtnback = (button) findviewbyid(r.id.btn_back); mbtnback.setvisibility(view.gone); mbtnscan = (button) findviewbyid(r.id.btn_scan); mbtnscan.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { startactivity(new intent(mainactivity.this, scanactivity.class)); } }); } }
布局文件
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <button android:id="@+id/btn_scan" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:textcolor="@color/white" android:padding="20dp" android:background="@drawable/btn_scan_result" android:text="扫一扫" /> <include android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignparenttop="true" layout="@layout/activity_scan_title" /> </relativelayout>
2、扫描页面
/** * 条形码扫描 * * @project app_zxing * @package com.android.scan * @author chenlin * @version 1.0 * @date 2014年3月6日 */ public class scanactivity extends activity implements callback { private static final float beep_volume = 0.10f; protected static final string result_text = "result"; protected static final string result_bitmap = "bitmap"; /** 扫描界面 */ private surfaceview msurfaceview; /** 自定义的view,就是我们看见的拍摄时中间的框框了 */ private viewfinderview mfindview; /** 解码处理类,负责调用另外的线程进行解码。 */ private captureactivityhandler mhandler; /** 判断是否创建了surfaceview */ private boolean hassurface; /** decodeformats 条形码,二维码等的集合 */ private vector<barcodeformat> mdecodeformats; /** 字符编码 */ private string characterset; /** 定时器 */ private inactivitytimer inactivitytimer; /** 媒体播放器 */ private mediaplayer mediaplayer; /** 是否播放声音 */ private boolean playbeep; /** 是否震动 */ private boolean vibrate; @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_scan); init(); } /** * 初始化 */ private void init() { msurfaceview = (surfaceview) findviewbyid(r.id.preview_view); mfindview = (viewfinderview) findviewbyid(r.id.viewfinder_view); cameramanager.init(getapplication()); hassurface = false; inactivitytimer = new inactivitytimer(this); } /** * 暂停后恢复时处理内容 */ @suppresswarnings("all") @override protected void onresume() { super.onresume(); // 先重新获得holder surfaceholder surfaceholder = msurfaceview.getholder(); if (hassurface) { initcamera(surfaceholder); } else { surfaceholder.addcallback(this); surfaceholder.settype(surfaceholder.surface_type_push_buffers); } mdecodeformats = null; characterset = null; playbeep = true; audiomanager audioservice = (audiomanager) getsystemservice(audio_service); // 如果当前是铃音模式,则继续准备下面的 蜂鸣提示音操作,如果是静音或者震动模式。就不要继续了。因为用户选择了无声的模式,我们就也不要出声了。 if (audioservice.getringermode() != audiomanager.ringer_mode_normal) { playbeep = false; } // 初始化播放声音 initbeepsound(); //播放 vibrate = true; } @override protected void onpause() { super.onpause(); if (mhandler != null) { mhandler.quitsynchronously(); mhandler = null; } // 关闭摄像头信息 cameramanager.get().closedriver(); } @override protected void ondestroy() { // 关闭定时器 inactivitytimer.shutdown(); super.ondestroy(); } /** * 处理扫描结果 * * @param result * @param barcode */ public void handledecode(result result, bitmap barcode) { // 添加定时器 inactivitytimer.onactivity(); // 响铃和震动 playbeepsoundandvibrate(); string resultstring = result.gettext(); if (textutils.isempty(resultstring)) { toastutil.show(this, "扫描失败"); scanactivity.this.finish(); } else { //扫描完成后传递结果 intent resultintent = new intent(); resultintent.setclass(scanactivity.this, scanresultactivity.class); resultintent.putextra(result_text, resultstring); bytearrayoutputstream baos = new bytearrayoutputstream(); barcode.compress(bitmap.compressformat.png, 100, baos); byte[] bitmapbyte = baos.tobytearray(); resultintent.putextra(result_bitmap, bitmapbyte); startactivity(resultintent); overridependingtransition(r.anim.activity_in_from_rigth, r.anim.activity_out_to_scale); scanactivity.this.finish(); } } private void initcamera(surfaceholder surfaceholder) { try { cameramanager.get().opendriver(surfaceholder); } catch (ioexception ioe) { return; } catch (runtimeexception e) { return; } if (mhandler == null) { mhandler = new captureactivityhandler(this, mdecodeformats, characterset); } } @override public void surfacechanged(surfaceholder holder, int format, int width, int height) { } /** * 在视图创建的时候初始化摄像头 */ @override public void surfacecreated(surfaceholder holder) { if (!hassurface) { hassurface = true; initcamera(holder); } } @override public void surfacedestroyed(surfaceholder holder) { hassurface = false; } public viewfinderview getviewfinderview() { return mfindview; } public handler gethandler() { return mhandler; } public void drawviewfinder() { mfindview.drawviewfinder(); } /** * 初始化声音资源 */ private void initbeepsound() { // 如果要播放声音并且没有播放器时 if (playbeep && mediaplayer == null) { // 设置声道流格式为音乐 setvolumecontrolstream(audiomanager.stream_music); mediaplayer = new mediaplayer(); mediaplayer.setaudiostreamtype(audiomanager.stream_music); // 设置声音完成后监听 mediaplayer.setoncompletionlistener(beeplistener); // 设定数据源,并准备播放 assetfiledescriptor file = getresources().openrawresourcefd(r.raw.beep); try { mediaplayer.setdatasource(file.getfiledescriptor(), file.getstartoffset(), file.getlength()); file.close(); mediaplayer.setvolume(beep_volume, beep_volume);// 设置音量 mediaplayer.prepare(); } catch (ioexception e) { mediaplayer = null; } } } private static final long vibrate_duration = 200l; /** * 响铃和震动 */ private void playbeepsoundandvibrate() { if (playbeep && mediaplayer != null) { mediaplayer.start(); } if (vibrate) { vibrator vibrator = (vibrator) getsystemservice(vibrator_service); // 震动一次 vibrator.vibrate(vibrate_duration); // 第一个参数,指代一个震动的频率数组。每两个为一组,每组的第一个为等待时间,第二个为震动时间。 // 比如 [2000,500,100,400],会先等待2000毫秒,震动500,再等待100,震动400 // 第二个参数,repest指代从 第几个索引(第一个数组参数) 的位置开始循环震动。 // 会一直保持循环,我们需要用 vibrator.cancel()主动终止 // vibrator.vibrate(new long[]{300,500},0); } } /** * 注册事件。当播放完毕一次后,重新指向流文件的开头,以准备下次播放。 */ private final mediaplayer.oncompletionlistener beeplistener = new mediaplayer.oncompletionlistener() { public void oncompletion(mediaplayer mediaplayer) { mediaplayer.seekto(0); } }; }
布局文件
<?xml version="1.0" encoding="utf-8"?> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <relativelayout android:layout_width="match_parent" android:layout_height="match_parent" > <surfaceview android:id="@+id/preview_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="center" /> <com.android.scan.view.viewfinderview android:id="@+id/viewfinder_view" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <include android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignparenttop="true" layout="@layout/activity_scan_title" /> </relativelayout> </framelayout>
3、结果页面
/** * * @project app_zxing * @package com.android.scan * @author chenlin * @version 1.0 * @date 2014年3月6日 * @note todo */ public class scanresultactivity extends activity { private edittext metscan; private button mbtnback; private button mbtncopy; private imageview mimageview; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_scan_result); initviews(); init(); } private void init() { final string result = getintent().getstringextra(scanactivity.result_text); metscan.settext(result); final clipboardmanager cm = (clipboardmanager) getsystemservice(clipboard_service); mbtnback.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { scanresultactivity.this.finish(); } }); mbtncopy.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { if (result!=null) { clipdata myclip = clipdata.newplaintext("text", result); cm.setprimaryclip(myclip); } } }); //设置图片信息 byte[] imgbyte = getintent().getbytearrayextra(scanactivity.result_bitmap); if (imgbyte != null) { drawable drawable = bitmaputil.byte2drawable(imgbyte); if (drawable != null) { mimageview.setimagedrawable(drawable); } } } // public void paste(view view){ // clipdata abc = myclipboard.getprimaryclip(); // clipdata.item item = abc.getitemat(0); // string text = item.gettext().tostring(); // pastefield.settext(text); // toast.maketext(getapplicationcontext(), "text pasted", // toast.length_short).show(); // } private void initviews() { metscan = (edittext) findviewbyid(r.id.et_scan_result); mbtnback = (button) findviewbyid(r.id.btn_back); mbtncopy = (button) findviewbyid(r.id.btn_copy); } }
四、代码下载
完整实例代码点击此处本站下载。
ps:这里再为大家推荐一款二维码在线生成工具供大家参考使用:
在线生成二维码工具(加强版)
更多关于android相关内容感兴趣的读者可查看本站专题:《android开发入门与进阶教程》、《android数据库操作技巧总结》、《android编程之activity操作技巧总结》、《android文件操作技巧汇总》、《android资源操作技巧汇总》、《android视图view技巧总结》及《android控件用法总结》
希望本文所述对大家android程序设计有所帮助。